diff --git a/moo/mooapp/mooapp.c b/moo/mooapp/mooapp.c index f6442871..6d9cc919 100644 --- a/moo/mooapp/mooapp.c +++ b/moo/mooapp/mooapp.c @@ -20,6 +20,7 @@ #include "mooapp/moopythonconsole.h" #include "mooapp/mooapp-python.h" #include "mooapp/moopython.h" +#include "moopython/mooplugin-python.h" #endif #define WANT_MOO_APP_CMD_CHARS @@ -46,8 +47,6 @@ /* moo-pygtk.c */ void initmoo (void); -/* mooplugin-python.c */ -gboolean _moo_python_plugin_init (void); static MooApp *moo_app_instance = NULL; @@ -720,27 +719,30 @@ moo_app_python_run_string (MooApp *app, } -GtkWidget *moo_app_get_python_console (G_GNUC_UNUSED MooApp *app) +GtkWidget* +moo_app_get_python_console (MooApp *app) { g_return_val_if_fail (MOO_IS_APP (app), NULL); g_return_val_if_fail (moo_app_python != NULL, NULL); - return GTK_WIDGET (moo_app_python->console); + return moo_python_get_console (moo_app_python); } -void moo_app_show_python_console (G_GNUC_UNUSED MooApp *app) +void +moo_app_show_python_console (MooApp *app) { g_return_if_fail (MOO_IS_APP (app)); g_return_if_fail (moo_app_python != NULL); - gtk_window_present (GTK_WINDOW (moo_app_python->console)); + gtk_window_present (GTK_WINDOW (moo_app_get_python_console (app))); } -void moo_app_hide_python_console (G_GNUC_UNUSED MooApp *app) +void +moo_app_hide_python_console (MooApp *app) { g_return_if_fail (MOO_IS_APP (app)); g_return_if_fail (moo_app_python != NULL); - gtk_widget_hide (GTK_WIDGET (moo_app_python->console)); + gtk_widget_hide (moo_app_get_python_console (app)); } @@ -774,6 +776,55 @@ const MooAppInfo*moo_app_get_info (MooApp *app) } +static char * +moo_app_get_user_data_dir (MooApp *app) +{ + char *basename = g_strdup_printf (".%s", app->priv->info->short_name); + char *dir = g_build_filename (g_get_home_dir (), basename, NULL); + g_free (basename); + return dir; +} + + +static char ** +moo_app_get_plugin_dirs (MooApp *app) +{ + char **dirs; + +#ifdef __WIN32__ + + const char *data_dir; + + if (app_dir[0]) + data_dir = app_dir; + else + data_dir = "."; + + dirs = g_new0 (char*, 2); + dirs[0] = g_build_filename (data_dir, MOO_PLUGIN_DIR_BASENAME, NULL); + +#else /* !__WIN32__ */ + + char *user_data_dir; + + dirs = g_new0 (char*, 3); + +#ifdef MOO_PLUGINS_DIR + dirs[0] = g_strdup (MOO_PLUGINS_DIR); +#else + dirs[0] = g_build_filename (".", MOO_PLUGIN_DIR_BASENAME, NULL); +#endif + + user_data_dir = moo_app_get_user_data_dir (app); + dirs[1] = g_build_filename (user_data_dir, MOO_PLUGIN_DIR_BASENAME, NULL); + g_free (user_data_dir); + +#endif /* !__WIN32__ */ + + return dirs; +} + + static gboolean moo_app_init_real (MooApp *app) { @@ -805,9 +856,9 @@ moo_app_init_real (MooApp *app) if (app->priv->use_editor) { - char *plugin_dir = NULL, *user_plugin_dir = NULL; char *lang_dir = NULL, *user_lang_dir = NULL; char *user_data_dir = NULL; + char **plugin_dirs; #ifdef __WIN32__ @@ -819,7 +870,6 @@ moo_app_init_real (MooApp *app) data_dir = "."; lang_dir = g_build_filename (data_dir, MOO_LANG_DIR_BASENAME, NULL); - plugin_dir = g_build_filename (data_dir, MOO_PLUGIN_DIR_BASENAME, NULL); #else /* !__WIN32__ */ @@ -829,14 +879,7 @@ moo_app_init_real (MooApp *app) lang_dir = g_build_filename (".", MOO_LANG_DIR_BASENAME, NULL); #endif -#ifdef MOO_PLUGINS_DIR - plugin_dir = g_strdup (MOO_PLUGINS_DIR); -#else - plugin_dir = g_build_filename (".", MOO_PLUGIN_DIR_BASENAME, NULL); -#endif - - user_data_dir = g_strdup_printf (".%s", app->priv->info->short_name); - user_plugin_dir = g_build_filename (user_data_dir, MOO_PLUGIN_DIR_BASENAME, NULL); + user_data_dir = moo_app_get_user_data_dir (app); user_lang_dir = g_build_filename (user_data_dir, MOO_LANG_DIR_BASENAME, NULL); #endif /* !__WIN32__ */ @@ -859,15 +902,13 @@ moo_app_init_real (MooApp *app) G_CALLBACK (all_editors_closed), app); + plugin_dirs = moo_app_get_plugin_dirs (app); moo_plugin_init_builtin (); - moo_plugin_read_dir (plugin_dir); - if (user_plugin_dir) - moo_plugin_read_dir (user_plugin_dir); + moo_plugin_read_dirs (plugin_dirs); + g_strfreev (plugin_dirs); g_free (lang_dir); - g_free (plugin_dir); g_free (user_lang_dir); - g_free (user_plugin_dir); g_free (user_data_dir); } @@ -891,13 +932,18 @@ static void start_python (G_GNUC_UNUSED MooApp *app) #ifdef MOO_USE_PYTHON if (app->priv->run_python) { + G_GNUC_UNUSED char **plugin_dirs; + moo_app_python = moo_python_new (); moo_python_start (moo_app_python, strv_length (app->priv->argv), app->priv->argv); #ifdef MOO_USE_PYGTK initmoo (); - _moo_python_plugin_init (); + + plugin_dirs = moo_app_get_plugin_dirs (app); + _moo_python_plugin_init (plugin_dirs); + g_strfreev (plugin_dirs); #endif } else diff --git a/moo/mooapp/moopython.c b/moo/mooapp/moopython.c index 751a23db..e210d323 100644 --- a/moo/mooapp/moopython.c +++ b/moo/mooapp/moopython.c @@ -76,7 +76,7 @@ static GObject *moo_python_constructor (GType type, MooPython *python; object = G_OBJECT_CLASS (moo_python_parent_class)->constructor (type, n_props, props); python = MOO_PYTHON (object); - python->console = moo_python_console_new (python); + python->_console = moo_python_console_new (python); return object; } @@ -278,3 +278,11 @@ static void init_logger (MooPython *python) PyErr_Print (); } } + + +gpointer +moo_python_get_console (MooPython *python) +{ + g_return_val_if_fail (MOO_IS_PYTHON (python), NULL); + return python->_console; +} diff --git a/moo/mooapp/moopython.h b/moo/mooapp/moopython.h index ade3ace3..1d153e72 100644 --- a/moo/mooapp/moopython.h +++ b/moo/mooapp/moopython.h @@ -45,7 +45,7 @@ struct _MooPython MooPythonLogFunc log_err_func; void *log_data; - struct _MooPythonConsole *console; + struct _MooPythonConsole *_console; }; struct _MooPythonClass @@ -87,6 +87,8 @@ gpointer moo_python_run_file (MooPython *python, gpointer fp, const char *filename); +gpointer moo_python_get_console (MooPython *python); + G_END_DECLS diff --git a/moo/mooedit/mooplugin.c b/moo/mooedit/mooplugin.c index 5306fe57..399d791a 100644 --- a/moo/mooedit/mooplugin.c +++ b/moo/mooedit/mooplugin.c @@ -744,7 +744,7 @@ out: } -void +static void moo_plugin_read_dir (const char *path) { GDir *dir; @@ -789,6 +789,14 @@ moo_plugin_read_dir (const char *path) } +void +moo_plugin_read_dirs (char **dirs) +{ + for ( ; dirs && *dirs; ++dirs) + moo_plugin_read_dir (*dirs); +} + + void _moo_window_attach_plugins (MooEditWindow *window) { diff --git a/moo/mooedit/mooplugin.h b/moo/mooedit/mooplugin.h index f57f67f4..c533f95a 100644 --- a/moo/mooedit/mooplugin.h +++ b/moo/mooedit/mooplugin.h @@ -193,7 +193,7 @@ const char *moo_plugin_description (MooPlugin *plugin); const char *moo_plugin_author (MooPlugin *plugin); const char *moo_plugin_version (MooPlugin *plugin); -void moo_plugin_read_dir (const char *dir); +void moo_plugin_read_dirs (char **dirs); void moo_plugin_init_builtin (void); void _moo_window_attach_plugins (MooEditWindow *window); diff --git a/moo/mooedit/mootextstylescheme.c b/moo/mooedit/mootextstylescheme.c index 0c42b0e1..cfb64913 100644 --- a/moo/mooedit/mootextstylescheme.c +++ b/moo/mooedit/mootextstylescheme.c @@ -283,9 +283,10 @@ static void fill_in_default_scheme (MooTextStyleScheme *scheme) { scheme->text_colors[MOO_TEXT_COLOR_CUR_LINE] = g_strdup ("#EEF6FF"); - scheme->bracket_match = new_style (NULL, "#FFFF99", FALSE, - FALSE, FALSE, FALSE, - MOO_TEXT_STYLE_BACKGROUND); + scheme->bracket_match = new_style (NULL, "#FFFF99", + FALSE, TRUE, FALSE, FALSE, + MOO_TEXT_STYLE_BACKGROUND | + MOO_TEXT_STYLE_BOLD); INSERT (DEF_STYLE_NORMAL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, 0); diff --git a/moo/moopython/Makefile.incl b/moo/moopython/Makefile.incl index 4210e475..5407b264 100644 --- a/moo/moopython/Makefile.incl +++ b/moo/moopython/Makefile.incl @@ -12,17 +12,26 @@ nodist_moopython_sources = moopython_built_sources = moopython_cleanfiles = +mooedit_defs_files = \ + $(moopython_srcdir)/mooeditor.defs \ + $(moopython_srcdir)/mooplugin.defs + +# mooutils_defs_files = \ +# $(moopython_srcdir)/mooutils.defs + moopython_extra_dist = \ $(moopython)/moo-pygtk.c \ $(moopython)/mooapp-pygtk.defs \ $(moopython)/mooapp-pygtk.override \ $(moopython)/mooapp-mod.c \ + $(mooedit_defs_files) \ $(moopython)/mooedit-pygtk.defs \ $(moopython)/mooedit-pygtk.override \ $(moopython)/mooedit-mod.c \ $(moopython)/mooterm-pygtk.defs \ $(moopython)/mooterm-pygtk.override \ $(moopython)/mooterm-mod.c \ + $(mooutils_defs_files) \ $(moopython)/mooutils-pygtk.defs \ $(moopython)/mooutils-pygtk.override \ $(moopython)/mooutils-mod.c @@ -33,6 +42,8 @@ moopython_sources += $(moopython)/mooutils-mod.c nodist_moopython_sources += $(moopython)/mooutils-pygtk.c moopython_built_sources += $(moopython)/mooutils-pygtk.c moopython_cleanfiles += $(moopython)/mooutils-pygtk.c +# $(moopython)/mooutils-pygtk.defs: $(mooutils_defs_files) +# touch $(moopython_srcdir)/mooutils-pygtk.defs endif MOO_BUILD_UTILS if MOO_BUILD_TERM @@ -47,6 +58,8 @@ moopython_sources += $(moopython)/mooedit-mod.c nodist_moopython_sources += $(moopython)/mooedit-pygtk.c moopython_built_sources += $(moopython)/mooedit-pygtk.c moopython_cleanfiles += $(moopython)/mooedit-pygtk.c +$(moopython)/mooedit-pygtk.defs: $(mooedit_defs_files) + touch $(moopython_srcdir)/mooedit-pygtk.defs endif MOO_BUILD_EDIT if MOO_BUILD_APP @@ -111,7 +124,12 @@ moo_extra_dist += $(moopython_extra_dist) ########################################################################### # Python plugin +mooplugin_python_sources = \ + $(moopython)/mooplugin-python.c \ + $(moopython)/mooplugin-python.h + if MOO_USE_PYGTK -moo_sources += $(moopython)/mooplugin-python.c +moo_sources += $(mooplugin_python_sources) endif -moo_extra_dist += $(moopython)/mooplugin-python.c + +moo_extra_dist += $(mooplugin_python_sources) diff --git a/moo/moopython/mooedit-pygtk.defs b/moo/moopython/mooedit-pygtk.defs index 5043137a..a00c8dae 100644 --- a/moo/moopython/mooedit-pygtk.defs +++ b/moo/moopython/mooedit-pygtk.defs @@ -7,13 +7,6 @@ (gtype-id "MOO_TYPE_EDIT_WINDOW") ) -(define-object Editor - (in-module "Moo") - (parent "GObject") - (c-name "MooEditor") - (gtype-id "MOO_TYPE_EDITOR") -) - (define-object Indenter (in-module "Moo") (parent "GObject") @@ -93,11 +86,6 @@ ;; From ../mooedit/moocmdview.h -(define-function moo_cmd_view_get_type - (c-name "moo_cmd_view_get_type") - (return-type "GType") -) - (define-function moo_cmd_view_new (c-name "moo_cmd_view_new") (is-constructor-of "MooCmdView") @@ -123,26 +111,6 @@ ;; From ../mooedit/mooedit.h -(define-function moo_edit_get_type - (c-name "moo_edit_get_type") - (return-type "GType") -) - -(define-function moo_edit_doc_status_get_type - (c-name "moo_edit_doc_status_get_type") - (return-type "GType") -) - -(define-function moo_edit_on_external_changes_get_type - (c-name "moo_edit_on_external_changes_get_type") - (return-type "GType") -) - -(define-function moo_edit_file_info_get_type - (c-name "moo_edit_file_info_get_type") - (return-type "GType") -) - (define-method get_filename (of-object "MooEdit") (c-name "moo_edit_get_filename") @@ -354,184 +322,6 @@ -;; From ../mooedit/mooeditor.h - -(define-function moo_editor_get_type - (c-name "moo_editor_get_type") - (return-type "GType") -) - -(define-function moo_editor_instance - (c-name "moo_editor_instance") - (return-type "MooEditor*") -) - -(define-method new_window - (of-object "MooEditor") - (c-name "moo_editor_new_window") - (return-type "MooEditWindow*") -) - -(define-method new_doc - (of-object "MooEditor") - (c-name "moo_editor_new_doc") - (return-type "MooEdit*") - (parameters - '("MooEditWindow*" "window") - ) -) - -(define-method open - (of-object "MooEditor") - (c-name "moo_editor_open") - (return-type "none") - (parameters - '("MooEditWindow*" "window") - '("GtkWidget*" "parent") - '("GSList*" "files") - ) -) - -(define-method open_file - (of-object "MooEditor") - (c-name "moo_editor_open_file") - (return-type "none") - (parameters - '("MooEditWindow*" "window") - '("GtkWidget*" "parent") - '("const-char*" "filename") - '("const-char*" "encoding") - ) -) - -(define-method get_doc - (of-object "MooEditor") - (c-name "moo_editor_get_doc") - (return-type "MooEdit*") - (parameters - '("const-char*" "filename") - ) -) - -(define-method get_active_doc - (of-object "MooEditor") - (c-name "moo_editor_get_active_doc") - (return-type "MooEdit*") -) - -(define-method get_active_window - (of-object "MooEditor") - (c-name "moo_editor_get_active_window") - (return-type "MooEditWindow*") -) - -(define-method set_active_window - (of-object "MooEditor") - (c-name "moo_editor_set_active_window") - (return-type "none") - (parameters - '("MooEditWindow*" "window") - ) -) - -(define-method set_active_doc - (of-object "MooEditor") - (c-name "moo_editor_set_active_doc") - (return-type "none") - (parameters - '("MooEdit*" "doc") - ) -) - -(define-method list_windows - (of-object "MooEditor") - (c-name "moo_editor_list_windows") - (return-type "GSList*") -) - -(define-method close_window - (of-object "MooEditor") - (c-name "moo_editor_close_window") - (return-type "gboolean") - (parameters - '("MooEditWindow*" "window") - ) -) - -(define-method close_doc - (of-object "MooEditor") - (c-name "moo_editor_close_doc") - (return-type "gboolean") - (parameters - '("MooEdit*" "doc") - ) -) - -(define-method close_docs - (of-object "MooEditor") - (c-name "moo_editor_close_docs") - (return-type "gboolean") - (parameters - '("GSList*" "list") - ) -) - -(define-method close_all - (of-object "MooEditor") - (c-name "moo_editor_close_all") - (return-type "gboolean") -) - -(define-method set_app_name - (of-object "MooEditor") - (c-name "moo_editor_set_app_name") - (return-type "none") - (parameters - '("const-char*" "name") - ) -) - -(define-method get_history - (of-object "MooEditor") - (c-name "moo_editor_get_history") - (return-type "MooHistoryList*") -) - -(define-method get_filter_mgr - (of-object "MooEditor") - (c-name "moo_editor_get_filter_mgr") - (return-type "MooFilterMgr*") -) - -(define-method get_ui_xml - (of-object "MooEditor") - (c-name "moo_editor_get_ui_xml") - (return-type "MooUIXML*") -) - -(define-method set_ui_xml - (of-object "MooEditor") - (c-name "moo_editor_set_ui_xml") - (return-type "none") - (parameters - '("MooUIXML*" "xml") - ) -) - -(define-method get_editor - (of-object "MooEditWindow") - (c-name "moo_edit_window_get_editor") - (return-type "MooEditor*") -) - -(define-method get_lang_mgr - (of-object "MooEditor") - (c-name "moo_editor_get_lang_mgr") - (return-type "MooLangMgr*") -) - - - ;; From ../mooedit/mooeditsearch.h (define-function moo_text_search_options_get_type @@ -1638,3 +1428,8 @@ ) +;; MooEditor +(include "mooeditor.defs") + +;; moo_plugin +(include "mooplugin.defs") diff --git a/moo/moopython/mooedit-pygtk.override b/moo/moopython/mooedit-pygtk.override index 4a0ebc0e..6cf4172d 100644 --- a/moo/moopython/mooedit-pygtk.override +++ b/moo/moopython/mooedit-pygtk.override @@ -7,6 +7,9 @@ headers #include "mooedit/mooeditsearch.h" #include "mooedit/mootextbuffer.h" #include "mooedit/moocmdview.h" +#include "mooedit/mootextiter.h" +#include "moopython/mooplugin-python.h" +#include "mooutils/mooutils-python.h" void moo_edit_add_constants (PyObject *module, const gchar *strip_prefix); void moo_edit_register_classes (PyObject *d); @@ -26,3 +29,36 @@ import moo.UIXML as PyMooUIXML_Type ignore-glob *_get_type %% +override moo_python_plugin_hook varargs +static PyObject * +_wrap_moo_python_plugin_hook (G_GNUC_UNUSED PyObject *self, PyObject *args) +{ + PyObject *event, *callback; + PyObject *data = NULL; + PyObject *result; + int len; + + len = PyTuple_GET_SIZE (args); + + if (len < 2) + return_TypeErr ("at least two arguments required"); + + event = PyTuple_GET_ITEM (args, 0); + + if (!PyString_Check (event)) + return_TypeErr ("event must be a string"); + + callback = PyTuple_GET_ITEM (args, 1); + + if (!PyCallable_Check (callback)) + return_TypeErr ("callback must be a callable"); + + if (len > 2) + data = PyTuple_GetSlice (args, 2, len); + + result = _moo_python_plugin_hook (PyString_AS_STRING (event), + callback, data); + Py_XDECREF (data); + + return result; +} diff --git a/moo/moopython/mooeditor.defs b/moo/moopython/mooeditor.defs new file mode 100644 index 00000000..800d16f0 --- /dev/null +++ b/moo/moopython/mooeditor.defs @@ -0,0 +1,176 @@ +(define-object Editor + (in-module "Moo") + (parent "GObject") + (c-name "MooEditor") + (gtype-id "MOO_TYPE_EDITOR") +) + + +(define-function moo_editor_instance + (c-name "moo_editor_instance") + (return-type "MooEditor*") +) + +(define-method new_window + (of-object "MooEditor") + (c-name "moo_editor_new_window") + (return-type "MooEditWindow*") +) + +(define-method new_doc + (of-object "MooEditor") + (c-name "moo_editor_new_doc") + (return-type "MooEdit*") + (parameters + '("MooEditWindow*" "window") + ) +) + +(define-method open + (of-object "MooEditor") + (c-name "moo_editor_open") + (return-type "none") + (parameters + '("MooEditWindow*" "window") + '("GtkWidget*" "parent") + '("GSList*" "files") + ) +) + +(define-method open_file + (of-object "MooEditor") + (c-name "moo_editor_open_file") + (return-type "none") + (parameters + '("MooEditWindow*" "window") + '("GtkWidget*" "parent") + '("const-char*" "filename") + '("const-char*" "encoding") + ) +) + +(define-method get_doc + (of-object "MooEditor") + (c-name "moo_editor_get_doc") + (return-type "MooEdit*") + (parameters + '("const-char*" "filename") + ) +) + +(define-method get_active_doc + (of-object "MooEditor") + (c-name "moo_editor_get_active_doc") + (return-type "MooEdit*") +) + +(define-method get_active_window + (of-object "MooEditor") + (c-name "moo_editor_get_active_window") + (return-type "MooEditWindow*") +) + +(define-method set_active_window + (of-object "MooEditor") + (c-name "moo_editor_set_active_window") + (return-type "none") + (parameters + '("MooEditWindow*" "window") + ) +) + +(define-method set_active_doc + (of-object "MooEditor") + (c-name "moo_editor_set_active_doc") + (return-type "none") + (parameters + '("MooEdit*" "doc") + ) +) + +(define-method list_windows + (of-object "MooEditor") + (c-name "moo_editor_list_windows") + (return-type "GSList*") +) + +(define-method close_window + (of-object "MooEditor") + (c-name "moo_editor_close_window") + (return-type "gboolean") + (parameters + '("MooEditWindow*" "window") + ) +) + +(define-method close_doc + (of-object "MooEditor") + (c-name "moo_editor_close_doc") + (return-type "gboolean") + (parameters + '("MooEdit*" "doc") + ) +) + +(define-method close_docs + (of-object "MooEditor") + (c-name "moo_editor_close_docs") + (return-type "gboolean") + (parameters + '("GSList*" "list") + ) +) + +(define-method close_all + (of-object "MooEditor") + (c-name "moo_editor_close_all") + (return-type "gboolean") +) + +(define-method set_app_name + (of-object "MooEditor") + (c-name "moo_editor_set_app_name") + (return-type "none") + (parameters + '("const-char*" "name") + ) +) + +(define-method get_history + (of-object "MooEditor") + (c-name "moo_editor_get_history") + (return-type "MooHistoryList*") +) + +(define-method get_filter_mgr + (of-object "MooEditor") + (c-name "moo_editor_get_filter_mgr") + (return-type "MooFilterMgr*") +) + +(define-method get_ui_xml + (of-object "MooEditor") + (c-name "moo_editor_get_ui_xml") + (return-type "MooUIXML*") +) + +(define-method set_ui_xml + (of-object "MooEditor") + (c-name "moo_editor_set_ui_xml") + (return-type "none") + (parameters + '("MooUIXML*" "xml") + ) +) + +(define-method get_editor + (of-object "MooEditWindow") + (c-name "moo_edit_window_get_editor") + (return-type "MooEditor*") +) + +(define-method get_lang_mgr + (of-object "MooEditor") + (c-name "moo_editor_get_lang_mgr") + (return-type "MooLangMgr*") +) diff --git a/moo/moopython/mooplugin-python.c b/moo/moopython/mooplugin-python.c index 94912bf7..53821cb1 100644 --- a/moo/moopython/mooplugin-python.c +++ b/moo/moopython/mooplugin-python.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- * - * moofind.c + * mooplugin-python.c * * Copyright (C) 2004-2005 by Yevgen Muntyan * @@ -12,81 +12,434 @@ * See COPYING file that comes with this distribution. */ +#include +#define NO_IMPORT_PYGOBJECT +#include "pygobject.h" + #ifdef HAVE_CONFIG_H #include "config.h" #endif + +#include "moopython/mooplugin-python.h" +#include "mooedit/mooplugin-macro.h" +#include "mooutils/mooutils-python.h" + #ifndef MOO_VERSION #define MOO_VERSION NULL #endif -#include "mooedit/mooplugin-macro.h" +#define MOO_PYTHON_PLUGIN_ID "moo-python" -#define PYTHON_PLUGIN_ID "python" +#define MOO_TYPE_PYTHON_PLUGIN (moo_python_plugin_get_type()) +#define MOO_IS_PYTHON_PLUGIN(obj_) (G_TYPE_CHECK_INSTANCE_TYPE (obj_, MOO_TYPE_PYTHON_PLUGIN)) +#define PLUGIN_SUFFIX ".py" -gboolean _moo_python_plugin_init (void); +typedef enum { + HOOK_NEW_WINDOW = 0, + HOOK_CLOSE_WINDOW, + HOOK_NEW_DOC, + HOOK_CLOSE_DOC, + HOOK_LAST +} HookType; +typedef struct { + HookType type; + PyObject *callback; + PyObject *data; +} Hook; typedef struct { MooPlugin parent; -} PythonPlugin; + + GHashTable *hook_ids; + GSList *hooks[HOOK_LAST]; + int last_id; +} MooPythonPlugin; + + +static Hook *hook_new (HookType type, + PyObject *callback, + PyObject *data); +static void hook_free (Hook *hook); + +static GType moo_python_plugin_get_type (void); + +static PyObject *moo_python_plugin_add_hook (MooPythonPlugin *plugin, + HookType type, + PyObject *callback, + PyObject *data); +static void moo_python_plugin_remove_hook (MooPythonPlugin *plugin, + int id); static gboolean -python_plugin_init (G_GNUC_UNUSED PythonPlugin *plugin) +moo_python_plugin_init (MooPythonPlugin *plugin) { + g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), FALSE); + g_return_val_if_fail (plugin->hook_ids == NULL, FALSE); + + plugin->hook_ids = g_hash_table_new (g_direct_hash, g_direct_equal); + return TRUE; } static void -python_plugin_deinit (G_GNUC_UNUSED PythonPlugin *plugin) +prepend_id (gpointer id, + G_GNUC_UNUSED gpointer hook, + GSList **list) { + *list = g_slist_prepend (*list, id); +} + +static void +moo_python_plugin_deinit (MooPythonPlugin *plugin) +{ + GSList *ids = NULL, *l; + + g_hash_table_foreach (plugin->hook_ids, (GHFunc) prepend_id, &ids); + + for (l = ids; l != NULL; l = l->next) + moo_python_plugin_remove_hook (plugin, GPOINTER_TO_INT (l->data)); + + g_hash_table_destroy (plugin->hook_ids); + plugin->hook_ids = NULL; + g_slist_free (ids); } static void -python_plugin_attach_win (G_GNUC_UNUSED PythonPlugin *plugin, - G_GNUC_UNUSED MooEditWindow *window) +call_hooks (MooPythonPlugin *plugin, + MooEditWindow *window, + MooEdit *doc, + HookType type) { -} + GSList *l; + PyObject *py_win, *py_doc; -static void -python_plugin_detach_win (G_GNUC_UNUSED PythonPlugin *plugin, - G_GNUC_UNUSED MooEditWindow *window) -{ + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); + g_return_if_fail (!doc || MOO_IS_EDIT (doc)); + g_return_if_fail (type < HOOK_LAST); + + py_win = pygobject_new (G_OBJECT (window)); + py_doc = doc ? pygobject_new (G_OBJECT (doc)) : NULL; + + for (l = plugin->hooks[type]; l != NULL; l = l->next) + { + PyObject *result; + Hook *hook = l->data; + + PyTuple_SET_ITEM (hook->data, 0, py_win); + if (py_doc) + PyTuple_SET_ITEM (hook->data, 1, py_doc); + + result = PyObject_Call (hook->callback, hook->data, NULL); + + PyTuple_SET_ITEM (hook->data, 0, NULL); + if (py_doc) + PyTuple_SET_ITEM (hook->data, 1, NULL); + + if (result) + { + Py_DECREF (result); + } + else + { + PyErr_Print (); + } + } + + Py_XDECREF (py_win); + Py_XDECREF (py_doc); } static void -python_plugin_attach_doc (G_GNUC_UNUSED PythonPlugin *plugin, - G_GNUC_UNUSED MooEdit *doc, - G_GNUC_UNUSED MooEditWindow *window) +moo_python_plugin_attach_win (MooPythonPlugin *plugin, + MooEditWindow *window) { + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); + call_hooks (plugin, window, NULL, HOOK_NEW_WINDOW); } + static void -python_plugin_detach_doc (G_GNUC_UNUSED PythonPlugin *plugin, - G_GNUC_UNUSED MooEdit *doc, - G_GNUC_UNUSED MooEditWindow *window) +moo_python_plugin_detach_win (MooPythonPlugin *plugin, + MooEditWindow *window) { + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); + call_hooks (plugin, window, NULL, HOOK_CLOSE_WINDOW); } -MOO_PLUGIN_DEFINE_INFO (python, PYTHON_PLUGIN_ID, - "Python", "A snake", +static void +moo_python_plugin_attach_doc (MooPythonPlugin *plugin, + MooEdit *doc, + MooEditWindow *window) +{ + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); + g_return_if_fail (MOO_IS_EDIT (doc)); + call_hooks (plugin, window, doc, HOOK_NEW_DOC); +} + + +static void +moo_python_plugin_detach_doc (MooPythonPlugin *plugin, + MooEdit *doc, + MooEditWindow *window) +{ + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); + g_return_if_fail (MOO_IS_EDIT (doc)); + call_hooks (plugin, window, doc, HOOK_CLOSE_DOC); +} + + +static void +moo_python_plugin_read_file (G_GNUC_UNUSED MooPythonPlugin *plugin, + const char *path) +{ + FILE *file; + PyObject *result, *main_dict, *main_mod; + + g_return_if_fail (path != NULL); + + file = fopen (path, "r"); + + if (!file) + { + perror ("fopen"); + return; + } + + main_mod = PyImport_AddModule ((char*) "__main__"); + g_return_if_fail (main_mod != NULL); + main_dict = PyModule_GetDict (main_mod); + + result = PyRun_File (file, path, Py_file_input, main_dict, main_dict); + fclose (file); + + if (result) + { + Py_XDECREF (result); + } + else + { + PyErr_Print (); + } +} + + +static void +moo_python_plugin_read_dir (MooPythonPlugin *plugin, + const char *path) +{ + GDir *dir; + const char *name; + + g_return_if_fail (path != NULL); + + dir = g_dir_open (path, 0, NULL); + + if (!dir) + return; + + while ((name = g_dir_read_name (dir))) + { + char *file_path, *prefix, *suffix; + + if (!g_str_has_suffix (name, PLUGIN_SUFFIX)) + continue; + + suffix = g_strrstr (name, PLUGIN_SUFFIX); + prefix = g_strndup (name, suffix - name); + + file_path = g_build_filename (path, name, NULL); + moo_python_plugin_read_file (plugin, file_path); + + g_free (prefix); + g_free (file_path); + } + + g_dir_close (dir); +} + + +static void +moo_python_plugin_read_dirs (MooPythonPlugin *plugin, + char **dirs) +{ + for ( ; dirs && *dirs; ++dirs) + moo_python_plugin_read_dir (plugin, *dirs); +} + + +MOO_PLUGIN_DEFINE_INFO (moo_python, MOO_PYTHON_PLUGIN_ID, + "Python plugin loader", "A snake", "Yevgen Muntyan ", MOO_VERSION); -MOO_PLUGIN_DEFINE_FULL (Python, python, - python_plugin_init, python_plugin_deinit, - python_plugin_attach_win, python_plugin_detach_win, - python_plugin_attach_doc, python_plugin_detach_doc, +MOO_PLUGIN_DEFINE_FULL (MooPython, moo_python, + moo_python_plugin_init, moo_python_plugin_deinit, + moo_python_plugin_attach_win, moo_python_plugin_detach_win, + moo_python_plugin_attach_doc, moo_python_plugin_detach_doc, NULL, 0, 0); gboolean -_moo_python_plugin_init (void) +_moo_python_plugin_init (char **dirs) { - python_plugin_params.visible = FALSE; - return moo_plugin_register (python_plugin_get_type ()); + gboolean result; + + moo_python_plugin_params.visible = FALSE; + result = moo_plugin_register (MOO_TYPE_PYTHON_PLUGIN); + + if (result) + { + MooPythonPlugin *plugin = moo_plugin_lookup (MOO_PYTHON_PLUGIN_ID); + g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), FALSE); + moo_python_plugin_read_dirs (plugin, dirs); + } + + return result; +} + + +static PyObject* +moo_python_plugin_add_hook (MooPythonPlugin *plugin, + HookType type, + PyObject *callback, + PyObject *data) +{ + int id = ++plugin->last_id; + Hook *hook = hook_new (type, callback, data); + plugin->hooks[type] = g_slist_prepend (plugin->hooks[type], hook); + g_hash_table_insert (plugin->hook_ids, GINT_TO_POINTER (id), hook); + return_Int (id); +} + + +PyObject* +_moo_python_plugin_hook (const char *event, + PyObject *callback, + PyObject *data) +{ + MooPythonPlugin *plugin; + PyObject *result; + + plugin = moo_plugin_lookup (MOO_PYTHON_PLUGIN_ID); + g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), NULL); + + if (!strcmp (event, "new-window")) + result = moo_python_plugin_add_hook (plugin, HOOK_NEW_WINDOW, callback, data); + else if (!strcmp (event, "close-window")) + result = moo_python_plugin_add_hook (plugin, HOOK_CLOSE_WINDOW, callback, data); + else if (!strcmp (event, "new-doc")) + result = moo_python_plugin_add_hook (plugin, HOOK_NEW_DOC, callback, data); + else if (!strcmp (event, "close-doc")) + result = moo_python_plugin_add_hook (plugin, HOOK_CLOSE_DOC, callback, data); + else + return_TypeErr ("invalid event type"); + + return result; +} + + +static Hook* +hook_new (HookType type, + PyObject *callback, + PyObject *data) +{ + int data_len, extra, i; + Hook *hook = g_new0 (Hook, 1); + + hook->type = type; + hook->callback = callback; + Py_INCREF (callback); + + data_len = data ? PyTuple_GET_SIZE (data) : 0; + + switch (type) + { + case HOOK_NEW_WINDOW: + case HOOK_CLOSE_WINDOW: + extra = 1; + break; + case HOOK_NEW_DOC: + case HOOK_CLOSE_DOC: + extra = 2; + break; + case HOOK_LAST: + g_return_val_if_reached (NULL); + } + + hook->data = PyTuple_New (data_len + extra); + + for (i = 0; i < data_len; ++i) + { + PyTuple_SET_ITEM (hook->data, i + extra, + PyTuple_GET_ITEM (data, i)); + Py_INCREF (PyTuple_GET_ITEM (data, i)); + } + + return hook; +} + + +static void +moo_python_plugin_remove_hook (MooPythonPlugin *plugin, + int id) +{ + Hook *hook; + + g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin)); + g_return_if_fail (id > 0); + + hook = g_hash_table_lookup (plugin->hook_ids, GINT_TO_POINTER (id)); + g_return_if_fail (hook != NULL); + + plugin->hooks[hook->type] = g_slist_remove (plugin->hooks[hook->type], hook); + g_hash_table_remove (plugin->hook_ids, GINT_TO_POINTER (id)); + + hook_free (hook); +} + + +static void +hook_free (Hook *hook) +{ + if (hook) + { + int i, extra = 0; + + switch (hook->type) + { + case HOOK_NEW_WINDOW: + case HOOK_CLOSE_WINDOW: + extra = 1; + break; + case HOOK_NEW_DOC: + case HOOK_CLOSE_DOC: + extra = 2; + break; + case HOOK_LAST: + g_critical ("%s: oops", G_STRLOC); + extra = 0; + break; + } + + for (i = 0; i < extra; ++i) + { + PyTuple_SET_ITEM (hook->data, i, Py_None); + Py_INCREF (Py_None); + } + + Py_XDECREF (hook->callback); + Py_XDECREF (hook->data); + g_free (hook); + } } diff --git a/moo/moopython/mooplugin-python.h b/moo/moopython/mooplugin-python.h new file mode 100644 index 00000000..62551e0a --- /dev/null +++ b/moo/moopython/mooplugin-python.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- + * + * mooplugin-python.h + * + * Copyright (C) 2004-2005 by Yevgen Muntyan + * + * 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. + * + * See COPYING file that comes with this distribution. + */ + +#ifndef __MOO_PLUGIN_PYTHON_H__ +#define __MOO_PLUGIN_PYTHON_H__ + +#include +#include "mooedit/mooplugin.h" + +G_BEGIN_DECLS + + +gboolean _moo_python_plugin_init (char **dirs); + +PyObject *_moo_python_plugin_hook (const char *event, + PyObject *callback, + PyObject *data); + + +G_END_DECLS + +#endif /* __MOO_PLUGIN_PYTHON_H__ */ diff --git a/moo/moopython/mooplugin.defs b/moo/moopython/mooplugin.defs new file mode 100644 index 00000000..0a1531f6 --- /dev/null +++ b/moo/moopython/mooplugin.defs @@ -0,0 +1,8 @@ +(define-function hook + (c-name "moo_python_plugin_hook") + (return-type "guint") + (parameters + '("const-char*" "event") + '("const-char*" "dummy") + ) +)