Resurrected pygtk bindings

master
Yevgen Muntyan 2010-11-28 04:15:47 -08:00
parent 4f68cca082
commit 334638111b
161 changed files with 32650 additions and 143 deletions

View File

@ -91,6 +91,7 @@ AC_DEFINE_UNQUOTED(MOO_WEBSITE,["$MOO_WEBSITE"],MOO_WEBSITE)
AC_DEFINE_UNQUOTED(MOO_WEB_CONTACT,["$MOO_WEB_CONTACT"],MOO_WEB_CONTACT)
MOO_AC_CHECK_OS
MOO_AC_PYTHON
AC_SUBST(MOO_TOP_SRCDIR,`cd $srcdir && pwd`)

108
m4/moo-pygtk.m4 Normal file
View File

@ -0,0 +1,108 @@
##############################################################################
# _MOO_AC_CHECK_PYGTK(action-if-found,action-if-not-found)
# checks pygtk stuff
#
AC_DEFUN([_MOO_AC_CHECK_PYGTK],[
AC_REQUIRE([MOO_AC_CHECK_OS])
PKG_CHECK_MODULES(PYGTK,pygtk-2.0 >= 2.6.0,[
AC_MSG_CHECKING([whether pygtk can be used])
save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
save_LIBS="$LIBS"
LIBS="$LIBS $PYGTK_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS"
save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $PYGTK_LDFLAGS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
AC_LINK_IFELSE([AC_LANG_SOURCE([[
#include <pygobject.h>
int main ()
{
PyObject *object = pygobject_new (NULL);
return 0;
}]])],[
AC_MSG_RESULT(yes)
PYGTK_DEFS_DIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
AC_SUBST(PYGTK_DEFS_DIR)
PYGTK_CODEGEN_DIR=`$PKG_CONFIG --variable=codegendir pygtk-2.0`
AC_SUBST(PYGTK_CODEGEN_DIR)
AC_MSG_NOTICE([pygtk defs dir: $PYGTK_DEFS_DIR])
m4_if([$1],[],[:],[$1])
],[
AC_MSG_RESULT([no])
m4_if([$2],[],[:],[$2])
])
CFLAGS="$save_CFLAGS"
CPPFLAGS="$save_CPPFLAGS"
LIBS="$save_LIBS"
LDFLAGS="$save_LDFLAGS"
],[
m4_if([$2],[],[:],[$2])
])
])
##############################################################################
# MOO_AC_PYTHON()
#
AC_DEFUN_ONCE([MOO_AC_PYTHON],[
AC_REQUIRE([MOO_AC_CHECK_OS])
MOO_ENABLE_PYTHON=true
_moo_want_python="auto"
_moo_python_version=2.2
AC_ARG_WITH([python],AC_HELP_STRING([--with-python], [whether to compile python support (default = YES)]),[
if test "x$with_python" = "xno"; then
MOO_ENABLE_PYTHON=false
elif test "x$with_python" = "xyes"; then
_moo_want_python="yes"
_moo_python_version="2.2"
else
_moo_want_python="yes"
_moo_python_version="$with_python"
fi
])
if test "x$MOO_OS_CYGWIN" = "xyes"; then
MOO_ENABLE_PYTHON=false
fi
if $MOO_ENABLE_PYTHON; then
MOO_ENABLE_PYTHON=false
MOO_AC_CHECK_PYTHON($_moo_python_version,[
_MOO_AC_CHECK_PYGTK([
MOO_ENABLE_PYTHON=true
_MOO_SPLIT_VERSION_PKG(PYGTK, pygtk-2.0)
AC_SUBST(PYGTK_VERSION)
AC_SUBST(PYGTK_MAJOR_VERSION)
AC_SUBST(PYGTK_MINOR_VERSION)
AC_SUBST(PYGTK_MICRO_VERSION)
])
])
if $MOO_ENABLE_PYTHON; then
AC_MSG_NOTICE([compiling python support])
elif test "x$_moo_want_python" = "xyes"; then
AC_MSG_ERROR([python support requested but python cannot be used])
elif test "x$_moo_want_python" = "xauto"; then
AC_MSG_WARN([disabled python support])
else
AC_MSG_NOTICE([disabled python support])
fi
fi
AM_CONDITIONAL(MOO_ENABLE_PYTHON, $MOO_ENABLE_PYTHON)
if $MOO_ENABLE_PYTHON; then
AC_DEFINE(MOO_ENABLE_PYTHON, 1, [build python bindings and plugin])
fi
if $MOO_ENABLE_PYTHON; then
MOO_CFLAGS="$MOO_CFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
MOO_CXXFLAGS="$MOO_CXXFLAGS $PYGTK_CFLAGS $PYTHON_INCLUDES"
MOO_LIBS="$MOO_LIBS $PYGTK_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYGTK_LDFLAGS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
fi
])

View File

@ -0,0 +1,96 @@
dnl ------------------------------------------------------------------------
dnl MOO_AM_PYTHON_DEVEL_CROSS_MINGW([action-if-found[,action-if-not-found]])
dnl
AC_DEFUN([MOO_AM_PYTHON_DEVEL_CROSS_MINGW],[
AC_REQUIRE([AC_PROG_SED]) dnl to get $SED set
AM_PATH_PYTHON
if test "x$WIN32_PYTHON_HOME" = x; then
AC_MSG_ERROR([WIN32_PYTHON_HOME environment variable must be set dnl
when cross-compiling with mingw])
fi
AC_MSG_CHECKING(host system python version)
if test "x$WIN32_PYTHON_VERSION" = x; then
# guess python version, very clever heuristics here
for _ac_python_minor in 3 4 5 6 7 8 9; do
if test -f "$WIN32_PYTHON_HOME/libs/libpython2$_ac_python_minor.a" -o \
-f "$WIN32_PYTHON_HOME/libs/python2$_ac_python_minor.lib" ;
then
_ac_pyversion="2.$_ac_python_minor"
break
fi
done
else
_ac_pyversion=$WIN32_PYTHON_VERSION
fi
if test "x$_ac_pyversion" = x; then
AC_MSG_ERROR([Could not determine Python version])
fi
AC_MSG_RESULT([$_ac_pyversion])
_ac_pyversion_no_dot=`echo $_ac_pyversion | $SED 's/^2\.*\([[3-9]]\).*/2\1/'`
AC_MSG_CHECKING(installation directory for python modules)
if test "x$WIN32_PYTHON_PKG_DIR" != x; then
_ac_pythondir="$WIN32_PYTHON_PKG_DIR"
else
_ac_pythondir="$WIN32_PYTHON_HOME/Lib/site-packages"
fi
AC_MSG_RESULT([$_ac_pythondir])
if test "x$WIN32_PYTHON_INCLUDES" != x; then
_ac_pyincludes="$WIN32_PYTHON_INCLUDES"
else
_ac_pyincludes="-I$WIN32_PYTHON_HOME/include"
fi
if test "x$WIN32_PYTHON_LIBS" != x; then
_ac_pylibs="$WIN32_PYTHON_LIBS"
else
_ac_pylibs="-L$WIN32_PYTHON_HOME/libs -lpython$_ac_pyversion_no_dot"
fi
if test "x$WIN32_PYTHON_LDFLAGS" != x; then
_ac_pyldflags="$WIN32_PYTHON_LDFLAGS"
else
_ac_pyldflags=
fi
_ac_have_pydev=false
_ac_save_CPPFLAGS="$CPPFLAGS"
_ac_save_LDFLAGS="$LDFLAGS"
_ac_save_LIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $_ac_pyincludes"
LDFLAGS="$LDFLAGS $_ac_pyldflags"
LIBS="$LIBS $_ac_pylibs"
AC_MSG_CHECKING(python headers and linker flags)
AC_TRY_LINK([#include <Python.h>],[Py_Initialize();],[
AC_MSG_RESULT([$_ac_pyincludes $_ac_pyldflags $_ac_pylibs])
_ac_have_pydev=true
],[
AC_MSG_RESULT(not found)
])
CPPFLAGS="$_ac_save_CPPFLAGS"
LDFLAGS="$_ac_save_LDFLAGS"
LIBS="$_ac_save_LIBS"
if $_ac_have_pydev; then
AC_SUBST(PYTHON_PLATFORM, [nt])
AC_SUBST(PYTHON_INCLUDES,[$_ac_pyincludes])
AC_SUBST(PYTHON_LIBS,[$_ac_pylibs])
AC_SUBST(PYTHON_EXTRA_LIBS,[])
AC_SUBST(PYTHON_LDFLAGS,[$_ac_pyldflags])
AC_SUBST(PYTHON_EXTRA_LDFLAGS,[])
AC_SUBST(pythondir,[$_ac_pythondir])
AC_SUBST(pyexecdir,[$_ac_pythondir])
AC_SUBST(pkgpythondir,[\${pythondir}/$PACKAGE])
AC_SUBST(pkgpyexecdir,[\${pythondir}/$PACKAGE])
m4_if([$1],[],[:],[$1])
else
m4_if([$2],[],[:],[$2])
fi
])
dnl
dnl end of MOO_AM_PYTHON_DEVEL_CROSS_MINGW
dnl --------------------------------------

145
m4/moo-python.m4 Normal file
View File

@ -0,0 +1,145 @@
##############################################################################
# _MOO_AC_PYTHON_DEVEL(action-if-found,action-if-not-found)
# checks python headers and libs. it's
# http://www.gnu.org/software/ac-archive/htmldoc/ac_python_devel.html,
# modified to allow actions if-found/if-not-found
#
AC_DEFUN([_MOO_AC_PYTHON_DEVEL],[
python_found=no
if test "$cross_compiling" = yes; then
test -z "$PYTHON_INCLUDES" || python_found=yes
else
# Check for distutils first
AC_MSG_CHECKING([for the distutils Python package])
$PYTHON -c "import distutils" 2>/dev/null
if test $? -eq 0; then
python_found=yes
AC_MSG_RESULT([yes])
else
python_found=no
AC_MSG_RESULT([no])
AC_MSG_WARN([cannot import Python module "distutils".
Please check your Python installation.])
fi
fi
# Check for Python include path
# if PYTHON_INCLUDES is set, do not do anything
if test $python_found = yes; then
AC_MSG_CHECKING([for Python include path])
if test -z "$PYTHON_INCLUDES"; then
python_path=`$PYTHON -c "import distutils.sysconfig; \
print distutils.sysconfig.get_python_inc();"`
if test -n "${python_path}"; then
python_path="-I$python_path"
fi
PYTHON_INCLUDES=$python_path
fi
AC_MSG_RESULT([$PYTHON_INCLUDES])
AC_SUBST([PYTHON_INCLUDES])
fi
# Check for Python linker flags
# if PYTHON_LIBS is set, do not do anything
if test $python_found = yes; then
AC_MSG_CHECKING([Python linker flags])
if test "x$PYTHON_LIBS" = "x"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
py_version=`$PYTHON -c "from distutils.sysconfig import *; \
from string import join; \
print join(get_config_vars('VERSION'))"`
if test "x$py_version" = "x[None]"; then
if test "x$PYTHON_VERSION" != "x"; then
py_version=$PYTHON_VERSION
else
py_version=`$PYTHON -c "import sys; \
print sys.version[[:3]]"`
fi
fi
PYTHON_LIBS=`$PYTHON -c "from distutils.sysconfig import *; \
from string import join; \
print '-L' + PREFIX + '/lib', \
'-lpython';"`$py_version
fi
AC_MSG_RESULT([$PYTHON_LIBS])
AC_SUBST([PYTHON_LIBS])
fi
# Check for Python extra linker flags
# if PYTHON_EXTRA_LIBS is set, do not do anything
if test $python_found = yes; then
if test "x$PYTHON_EXTRA_LIBS" = "x"; then
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print conf('LOCALMODLIBS'), conf('LIBS')"`
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print conf('LDFLAGS')"`
fi
AC_MSG_CHECKING([Python extra libs])
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
AC_MSG_CHECKING([Python extra linker flags])
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
AC_SUBST([PYTHON_EXTRA_LIBS])
AC_SUBST([PYTHON_EXTRA_LDFLAGS])
fi
if test $python_found = yes; then
m4_if([$1],[],[:],[$1])
else
m4_if([$2],[],[:],[$2])
fi
])
##############################################################################
# _MOO_AC_CHECK_PYTHON_UNIX(min-version,action-if-found,action-if-not-found)
# checks python stuff when building for unix
#
AC_DEFUN([_MOO_AC_CHECK_PYTHON_UNIX],[
AM_PATH_PYTHON([$1],[
_MOO_AC_PYTHON_DEVEL([
python_found=yes
],[
AC_MSG_WARN([Found python interpreter but no development headers or libraries])
python_found=no
])
],[
python_found=no
])
if test x$python_found = xyes; then
m4_if([$2],[],[:],[$2])
else
PYTHON_INCLUDES=""
PYTHON_LIBS=""
PYTHON_EXTRA_LIBS=""
m4_if([$3],[],[:],[$3])
fi
])
##############################################################################
# MOO_AC_CHECK_PYTHON(min-version,action-if-found,action-if-not-found)
# checks for python, python includes and libs
#
AC_DEFUN([MOO_AC_CHECK_PYTHON],[
AC_MSG_NOTICE([checking for headers and libs required to compile python extensions])
AC_REQUIRE([MOO_AC_CHECK_OS])
if test x$MOO_OS_CYGWIN != xyes; then
if test x$MOO_OS_MINGW = xyes; then
MOO_AM_PYTHON_DEVEL_CROSS_MINGW([$2],[$3])
else
_MOO_AC_CHECK_PYTHON_UNIX([$1],[$2],[$3])
fi
fi
])

View File

@ -34,6 +34,7 @@ include mooedit/Makefile.incl
include eggsmclient/Makefile.incl
include mooapp/Makefile.incl
include mooscript/Makefile.incl
include moopython/Makefile.incl
include plugins/Makefile.incl
include medit-app/Makefile.incl

View File

@ -16,9 +16,6 @@
#include <config.h>
#include "mooapp/mooapp.h"
#include "mooedit/mooplugin.h"
#ifdef MOO_ENABLE_PYTHON
#include "plugins/moopython/moopython-builtin.h"
#endif
#include "mooutils/mooi18n.h"
#include "mooutils/mooutils-fs.h"
#include "mooutils/mooutils-misc.h"
@ -73,9 +70,6 @@ MOO_DEFINE_TYPE_STATIC (MeditApp, medit_app, MOO_TYPE_APP)
static void
medit_app_init_plugins (G_GNUC_UNUSED MooApp *app)
{
#ifdef MOO_ENABLE_PYTHON
_moo_python_builtin_init ();
#endif
moo_plugin_init_builtin ();
moo_plugin_read_dirs ();
}

View File

@ -25,7 +25,6 @@
#include "mooapp-info.h"
#include "mooappabout.h"
#include "mooscript/lua/moolua.h"
#include "mooscript/python/moopython.h"
#include "mooedit/mooeditprefs.h"
#include "mooedit/mooeditor.h"
#include "mooedit/mooplugin.h"
@ -77,7 +76,7 @@ static struct {
static volatile int signal_received;
struct MooAppPrivate {
struct _MooAppPrivate {
MooEditor *editor;
char *rc_files[2];
@ -493,10 +492,10 @@ moo_app_run_script (MooApp *app,
medit_lua_run_string (script + strlen (SCRIPT_PREFIX_LUA));
else if (g_str_has_prefix (script, SCRIPT_PREFIX_LUA_FILE))
medit_lua_run_file (script + strlen (SCRIPT_PREFIX_LUA_FILE));
else if (g_str_has_prefix (script, SCRIPT_PREFIX_PYTHON))
moo_python_run_string (script + strlen (SCRIPT_PREFIX_PYTHON));
else if (g_str_has_prefix (script, SCRIPT_PREFIX_PYTHON_FILE))
moo_python_run_file (script + strlen (SCRIPT_PREFIX_PYTHON_FILE));
// else if (g_str_has_prefix (script, SCRIPT_PREFIX_PYTHON))
// moo_python_run_string (script + strlen (SCRIPT_PREFIX_PYTHON));
// else if (g_str_has_prefix (script, SCRIPT_PREFIX_PYTHON_FILE))
// moo_python_run_file (script + strlen (SCRIPT_PREFIX_PYTHON_FILE));
else
medit_lua_run_string (script);
}

View File

@ -29,17 +29,17 @@ G_BEGIN_DECLS
#define MOO_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_APP, MooAppClass))
typedef struct MooApp MooApp;
typedef struct MooAppPrivate MooAppPrivate;
typedef struct MooAppClass MooAppClass;
typedef struct _MooApp MooApp;
typedef struct _MooAppPrivate MooAppPrivate;
typedef struct _MooAppClass MooAppClass;
struct MooApp
struct _MooApp
{
GObject parent;
MooAppPrivate *priv;
};
struct MooAppClass
struct _MooAppClass
{
GObjectClass parent_class;

View File

@ -22,7 +22,7 @@ G_BEGIN_DECLS
#define MOO_EDIT_IS_UNTITLED(edit) (!(edit)->priv->file)
struct MooEditPrivate {
struct _MooEditPrivate {
MooEditView *view;
MooEditor *editor;

View File

@ -35,17 +35,17 @@ G_BEGIN_DECLS
#define MOO_EDIT_IS_CLEAN(edit) (moo_edit_get_status (edit) & MOO_EDIT_CLEAN)
#define MOO_EDIT_IS_BUSY(edit) (moo_edit_get_state (edit) != MOO_EDIT_STATE_NORMAL)
typedef struct MooEditPrivate MooEditPrivate;
typedef struct MooEditClass MooEditClass;
typedef struct _MooEditPrivate MooEditPrivate;
typedef struct _MooEditClass MooEditClass;
struct MooEdit
struct _MooEdit
{
GObject parent;
MooEditConfig *config;
MooEditPrivate *priv;
};
struct MooEditClass
struct _MooEditClass
{
GObjectClass parent_class;

View File

@ -20,7 +20,7 @@
G_BEGIN_DECLS
struct MooEditBufferPrivate
struct _MooEditBufferPrivate
{
MooEditView *view;
};

View File

@ -29,16 +29,16 @@ G_BEGIN_DECLS
#define MOO_IS_EDIT_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_EDIT_BUFFER))
#define MOO_EDIT_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_EDIT_BUFFER, MooEditBufferClass))
typedef struct MooEditBufferPrivate MooEditBufferPrivate;
typedef struct MooEditBufferClass MooEditBufferClass;
typedef struct _MooEditBufferPrivate MooEditBufferPrivate;
typedef struct _MooEditBufferClass MooEditBufferClass;
struct MooEditBuffer
struct _MooEditBuffer
{
MooTextBuffer parent;
MooEditBufferPrivate *priv;
};
struct MooEditBufferClass
struct _MooEditBufferClass
{
MooTextBufferClass parent_class;
};

View File

@ -34,7 +34,7 @@ typedef struct VarArray VarArray;
typedef struct Value Value;
struct MooEditConfigPrivate {
struct _MooEditConfigPrivate {
MOO_IP_ARRAY_ELMS (Value, values);
};

View File

@ -29,17 +29,17 @@ G_BEGIN_DECLS
#define MOO_IS_EDIT_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_EDIT_CONFIG))
#define MOO_EDIT_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_EDIT_CONFIG, MooEditConfigClass))
typedef struct MooEditConfig MooEditConfig;
typedef struct MooEditConfigPrivate MooEditConfigPrivate;
typedef struct MooEditConfigClass MooEditConfigClass;
typedef struct _MooEditConfig MooEditConfig;
typedef struct _MooEditConfigPrivate MooEditConfigPrivate;
typedef struct _MooEditConfigClass MooEditConfigClass;
struct MooEditConfig
struct _MooEditConfig
{
GObject object;
MooEditConfigPrivate *priv;
};
struct MooEditConfigClass
struct _MooEditConfigClass
{
GObjectClass object_class;
};
@ -92,9 +92,6 @@ void moo_edit_config_unset_by_source (MooEditConfig *config,
gboolean moo_edit_config_parse_bool (const char *string,
gboolean *value);
void moo_edit_config_update (MooEditConfig *config,
const char *lang_id);
G_END_DECLS

View File

@ -30,16 +30,16 @@ G_BEGIN_DECLS
#define MOO_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_EDITOR))
#define MOO_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_EDITOR, MooEditorClass))
typedef struct MooEditorPrivate MooEditorPrivate;
typedef struct MooEditorClass MooEditorClass;
typedef struct _MooEditorPrivate MooEditorPrivate;
typedef struct _MooEditorClass MooEditorClass;
struct MooEditor
struct _MooEditor
{
GObject base;
MooEditorPrivate *priv;
};
struct MooEditorClass
struct _MooEditorClass
{
GObjectClass base_class;

View File

@ -7,13 +7,13 @@
G_BEGIN_DECLS
typedef struct MooFileEnc MooFileEnc;
typedef struct _MooFileEnc MooFileEnc;
typedef struct MooEdit MooEdit;
typedef struct MooEditView MooEditView;
typedef struct MooEditBuffer MooEditBuffer;
typedef struct MooEditWindow MooEditWindow;
typedef struct MooEditor MooEditor;
typedef struct _MooEdit MooEdit;
typedef struct _MooEditView MooEditView;
typedef struct _MooEditBuffer MooEditBuffer;
typedef struct _MooEditWindow MooEditWindow;
typedef struct _MooEditor MooEditor;
MOO_DECLARE_OBJECT_ARRAY (MooEditArray, moo_edit_array, MooEdit)
MOO_DECLARE_OBJECT_ARRAY (MooEditViewArray, moo_edit_view_array, MooEditView)

View File

@ -24,7 +24,7 @@ G_BEGIN_DECLS
#define PROGRESS_WIDTH 300
#define PROGRESS_HEIGHT 100
struct MooEditViewPrivate
struct _MooEditViewPrivate
{
MooEdit *doc;
MooEditBuffer *buffer;

View File

@ -29,16 +29,16 @@ G_BEGIN_DECLS
#define MOO_IS_EDIT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_EDIT_VIEW))
#define MOO_EDIT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_EDIT_VIEW, MooEditViewClass))
typedef struct MooEditViewPrivate MooEditViewPrivate;
typedef struct MooEditViewClass MooEditViewClass;
typedef struct _MooEditViewPrivate MooEditViewPrivate;
typedef struct _MooEditViewClass MooEditViewClass;
struct MooEditView
struct _MooEditView
{
MooTextView parent;
MooEditViewPrivate *priv;
};
struct MooEditViewClass
struct _MooEditViewClass
{
MooTextViewClass parent_class;
};

View File

@ -77,7 +77,7 @@ typedef struct {
static GHashTable *action_checks; /* char* -> ActionCheck* */
static GSList *windows;
struct MooEditWindowPrivate {
struct _MooEditWindowPrivate {
MooEditor *editor;
guint statusbar_idle;

View File

@ -33,17 +33,17 @@ G_BEGIN_DECLS
#define MOO_IS_EDIT_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_EDIT_WINDOW))
#define MOO_EDIT_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_EDIT_WINDOW, MooEditWindowClass))
typedef struct MooEditWindowPrivate MooEditWindowPrivate;
typedef struct MooEditWindowClass MooEditWindowClass;
typedef struct _MooEditWindowPrivate MooEditWindowPrivate;
typedef struct _MooEditWindowClass MooEditWindowClass;
struct MooEditWindow
struct _MooEditWindow
{
MooWindow parent;
MooEditWindowPrivate *priv;
MooBigPaned *paned;
};
struct MooEditWindowClass
struct _MooEditWindowClass
{
MooWindowClass parent_class;
@ -93,9 +93,6 @@ MooEditView *moo_edit_window_get_nth_view (MooEditWindow *window,
MooEditArray *moo_edit_window_get_docs (MooEditWindow *window);
MooEditViewArray*moo_edit_window_get_views (MooEditWindow *window);
void moo_edit_window_set_title_prefix (MooEditWindow *window,
const char *prefix);
/* sinks widget */
MooPane *moo_edit_window_add_pane (MooEditWindow *window,
const char *user_id,

View File

@ -6,7 +6,7 @@
G_BEGIN_DECLS
struct MooFileEnc {
struct _MooFileEnc {
GFile *file;
char *encoding;
};

View File

@ -29,10 +29,10 @@ G_BEGIN_DECLS
#define MOO_INDENTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_INDENTER, MooIndenterClass))
typedef struct MooIndenter MooIndenter;
typedef struct MooIndenterClass MooIndenterClass;
typedef struct _MooIndenter MooIndenter;
typedef struct _MooIndenterClass MooIndenterClass;
struct MooIndenter
struct _MooIndenter
{
GObject parent;
MooEdit *doc;
@ -41,7 +41,7 @@ struct MooIndenter
guint indent;
};
struct MooIndenterClass
struct _MooIndenterClass
{
GObjectClass parent_class;

View File

@ -31,9 +31,9 @@ G_BEGIN_DECLS
#define MOO_IS_LANG_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_LANG_MGR))
#define MOO_LANG_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_LANG_MGR, MooLangMgrClass))
typedef struct MooLangMgrClass MooLangMgrClass;
typedef struct _MooLangMgrClass MooLangMgrClass;
struct MooLangMgr {
struct _MooLangMgr {
GObject base;
GtkSourceLanguageManager *lang_mgr;
@ -50,7 +50,7 @@ struct MooLangMgr {
gboolean modified;
};
struct MooLangMgrClass
struct _MooLangMgrClass
{
GObjectClass base_class;
};

View File

@ -27,7 +27,7 @@ G_BEGIN_DECLS
#define MOO_LANG_MGR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_LANG_MGR, MooLangMgr))
#define MOO_IS_LANG_MGR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_LANG_MGR))
typedef struct MooLangMgr MooLangMgr;
typedef struct _MooLangMgr MooLangMgr;
GType moo_lang_mgr_get_type (void) G_GNUC_CONST;

View File

@ -23,14 +23,14 @@
typedef struct MooFileViewPrivate MooFileViewPrivate;
struct MooFileView
struct _MooFileView
{
GtkVBox vbox;
GtkWidget *toolbar;
MooFileViewPrivate *priv;
};
struct MooFileViewClass
struct _MooFileViewClass
{
GtkVBoxClass vbox_class;

View File

@ -29,8 +29,8 @@ G_BEGIN_DECLS
#define MOO_IS_FILE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_FILE_VIEW))
#define MOO_FILE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_FILE_VIEW, MooFileViewClass))
typedef struct MooFileView MooFileView;
typedef struct MooFileViewClass MooFileViewClass;
typedef struct _MooFileView MooFileView;
typedef struct _MooFileViewClass MooFileViewClass;
GType moo_file_view_get_type (void) G_GNUC_CONST;

View File

@ -82,7 +82,7 @@ struct DndInfo {
};
struct MooIconViewPrivate {
struct _MooIconViewPrivate {
GtkTreeModel *model;
CellInfo pixbuf;

View File

@ -36,17 +36,17 @@ G_BEGIN_DECLS
#define MOO_ICON_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_ICON_VIEW, MooIconViewClass))
typedef struct MooIconView MooIconView;
typedef struct MooIconViewPrivate MooIconViewPrivate;
typedef struct MooIconViewClass MooIconViewClass;
typedef struct _MooIconView MooIconView;
typedef struct _MooIconViewPrivate MooIconViewPrivate;
typedef struct _MooIconViewClass MooIconViewClass;
struct MooIconView
struct _MooIconView
{
GtkVBox vbox;
MooIconViewPrivate *priv;
};
struct MooIconViewClass
struct _MooIconViewClass
{
GtkVBoxClass vbox_class;

View File

@ -0,0 +1,33 @@
moo_python_sources =
built_moo_python_sources =
include moopython/pygtk/Makefile.incl
moo_python_sources += \
moopython/moopython-builtin.h \
moopython/moopython-builtin.c \
moopython/moopython-api.h \
moopython/moopython-loader.h \
moopython/moopython-loader.c \
moopython/moopython-utils.h \
moopython/moopython-utils.c
if MOO_ENABLE_PYTHON
moo_sources += $(moo_python_sources)
built_moo_sources += $(built_moo_python_sources)
endif
EXTRA_DIST += \
$(moo_python_sources) \
moopython/codegen/__init__.py \
moopython/codegen/argtypes.py \
moopython/codegen/argtypes_m.py \
moopython/codegen/codegen.py \
moopython/codegen/definitions.py \
moopython/codegen/defsparser.py \
moopython/codegen/docgen.py \
moopython/codegen/mergedefs.py \
moopython/codegen/mkskel.py \
moopython/codegen/override.py \
moopython/codegen/reversewrapper.py \
moopython/codegen/scmexpr.py

View File

@ -0,0 +1,4 @@
This is pygtk's codegen (http://pygtk.org/), slightly
modified for cross-compiling and compiling with pygtk-2.6
(and it also removes senseless warnings about not-wrapped
methods unless explicitly asked for those).

View File

@ -0,0 +1,15 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
__all__ = [
'argtypes',
'codegen',
'definitions',
'defsparser',
'docextract',
'docgen',
'h2def',
'mergedefs',
'mkskel',
'override',
'scmexpr'
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
from argtypes import ArgType, matcher
class StrvArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
if pdflt != 'NULL': raise TypeError("Only NULL is supported as a default char** value")
info.varlist.add('char', '**' + pname + ' = ' + pdflt)
else:
info.varlist.add('char', '**' + pname)
info.arglist.append(pname)
if pnull:
info.add_parselist('O&', ['_moo_pyobject_to_strv', '&' + pname], [pname])
else:
info.add_parselist('O&', ['_moo_pyobject_to_strv_no_null', '&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
if ownsreturn:
# have to free result ...
info.varlist.add('char', '**ret')
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = _moo_strv_to_pyobject (ret);\n' +
' g_strfreev (ret);\n' +
' return py_ret;')
else:
info.varlist.add('char', '**ret')
info.codeafter.append(' return _moo_strv_to_pyobject (ret);')
class StringSListArg(ArgType):
def write_return(self, ptype, ownsreturn, info):
if ownsreturn:
# have to free result ...
info.varlist.add('GSList', '*ret')
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = _moo_string_slist_to_pyobject (ret);\n' +
' g_slist_foreach (ret, (GFunc) g_free, NULL);\n' +
' g_slist_free (ret);\n' +
' return py_ret;')
else:
info.varlist.add('GSList', '*ret')
info.codeafter.append(' return _moo_string_slist_to_pyobject (ret);')
class ObjectSListArg(ArgType):
def write_return(self, ptype, ownsreturn, info):
if ownsreturn:
# have to free result ...
info.varlist.add('GSList', '*ret')
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = _moo_object_slist_to_pyobject (ret);\n' +
' g_slist_foreach (ret, (GFunc) g_object_unref, NULL);\n' +
' g_slist_free (ret);\n' +
' return py_ret;')
else:
info.varlist.add('GSList', '*ret')
info.codeafter.append(' return _moo_object_slist_to_pyobject (ret);')
class NoRefObjectSListArg(ArgType):
def write_return(self, ptype, ownsreturn, info):
if ownsreturn:
# have to free result ...
info.varlist.add('GSList', '*ret')
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = _moo_object_slist_to_pyobject (ret);\n' +
' g_slist_free (ret);\n' +
' return py_ret;')
else:
info.varlist.add('GSList', '*ret')
info.codeafter.append(' return _moo_object_slist_to_pyobject (ret);')
arg = StrvArg()
matcher.register('strv', arg)
arg = StringSListArg()
matcher.register('string-slist', arg)
arg = ObjectSListArg()
matcher.register('object-slist', arg)
arg = NoRefObjectSListArg()
matcher.register('no-ref-object-slist', arg)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,547 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import copy
import sys
def get_valid_scheme_definitions(defs):
return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]
def unescape(s):
s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t')
return s.replace('\r', '\\r').replace('\n', '\\n')
def make_docstring(lines):
return "(char *) " + '\n'.join(['"%s"' % (unescape(s),) for s in lines])
# New Parameter class, wich emulates a tuple for compatibility reasons
class Parameter(object):
def __init__(self, ptype, pname, pdflt, pnull, pdir=None):
self.ptype = ptype
self.pname = pname
self.pdflt = pdflt
self.pnull = pnull
self.pdir = pdir
def __len__(self): return 4
def __getitem__(self, i):
return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
def merge(self, old):
if old.pdflt is not None:
self.pdflt = old.pdflt
if old.pnull is not None:
self.pnull = old.pnull
# Parameter for property based constructors
class Property(object):
def __init__(self, pname, optional, argname):
self.pname = pname
self.optional = optional
self.argname = argname
def merge(self, old):
if old.optional is not None:
self.optional = old.optional
if old.argname is not None:
self.argname = old.argname
class Definition:
docstring = "NULL"
def __init__(self, *args):
"""Create a new defs object of this type. The arguments are the
components of the definition"""
raise RuntimeError, "this is an abstract class"
def merge(self, old):
"""Merge in customisations from older version of definition"""
raise RuntimeError, "this is an abstract class"
def write_defs(self, fp=sys.stdout):
"""write out this definition in defs file format"""
raise RuntimeError, "this is an abstract class"
def guess_return_value_ownership(self):
"return 1 if caller owns return value"
if getattr(self, 'is_constructor_of', False):
self.caller_owns_return = True
elif self.ret in ('char*', 'gchar*', 'string'):
self.caller_owns_return = True
else:
self.caller_owns_return = False
class ObjectDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.parent = None
self.c_name = None
self.typecode = None
self.fields = []
self.implements = []
self.class_init_func = None
self.has_new_constructor_api = False
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'parent':
self.parent = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'fields':
for parg in arg[1:]:
self.fields.append((parg[0], parg[1]))
elif arg[0] == 'implements':
self.implements.append(arg[1])
def merge(self, old):
# currently the .h parser doesn't try to work out what fields of
# an object structure should be public, so we just copy the list
# from the old version ...
self.fields = old.fields
self.implements = old.implements
def write_defs(self, fp=sys.stdout):
fp.write('(define-object ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\n')
if self.parent != (None, None):
fp.write(' (parent "' + self.parent + '")\n')
for interface in self.implements:
fp.write(' (implements "' + interface + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.fields:
fp.write(' (fields\n')
for (ftype, fname) in self.fields:
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
fp.write(' )\n')
fp.write(')\n\n')
class InterfaceDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.vtable = None
self.fields = []
self.interface_info = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'vtable':
self.vtable = arg[1]
if self.vtable is None:
self.vtable = self.c_name + "Iface"
def write_defs(self, fp=sys.stdout):
fp.write('(define-interface ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
fp.write(')\n\n')
class EnumDef(Definition):
def __init__(self, name, *args):
self.deftype = 'enum'
self.name = name
self.in_module = None
self.c_name = None
self.typecode = None
self.values = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.in_module = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'values':
for varg in arg[1:]:
self.values.append((varg[0], varg[1]))
def merge(self, old):
pass
def write_defs(self, fp=sys.stdout):
fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
if self.in_module:
fp.write(' (in-module "' + self.in_module + '")\n')
fp.write(' (c-name "' + self.c_name + '")\n')
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.values:
fp.write(' (values\n')
for name, val in self.values:
fp.write(' \'("' + name + '" "' + val + '")\n')
fp.write(' )\n')
fp.write(')\n\n')
class FlagsDef(EnumDef):
def __init__(self, *args):
apply(EnumDef.__init__, (self,) + args)
self.deftype = 'flags'
class BoxedDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.copy = None
self.release = None
self.fields = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'copy-func':
self.copy = arg[1]
elif arg[0] == 'release-func':
self.release = arg[1]
elif arg[0] == 'fields':
for parg in arg[1:]:
self.fields.append((parg[0], parg[1]))
def merge(self, old):
# currently the .h parser doesn't try to work out what fields of
# an object structure should be public, so we just copy the list
# from the old version ...
self.fields = old.fields
def write_defs(self, fp=sys.stdout):
fp.write('(define-boxed ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.copy:
fp.write(' (copy-func "' + self.copy + '")\n')
if self.release:
fp.write(' (release-func "' + self.release + '")\n')
if self.fields:
fp.write(' (fields\n')
for (ftype, fname) in self.fields:
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
fp.write(' )\n')
fp.write(')\n\n')
class PointerDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.fields = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'fields':
for parg in arg[1:]:
self.fields.append((parg[0], parg[1]))
def merge(self, old):
# currently the .h parser doesn't try to work out what fields of
# an object structure should be public, so we just copy the list
# from the old version ...
self.fields = old.fields
def write_defs(self, fp=sys.stdout):
fp.write('(define-pointer ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.fields:
fp.write(' (fields\n')
for (ftype, fname) in self.fields:
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
fp.write(' )\n')
fp.write(')\n\n')
class MethodDefBase(Definition):
def __init__(self, name, *args):
dump = 0
self.name = name
self.ret = None
self.caller_owns_return = None
self.unblock_threads = None
self.c_name = None
self.typecode = None
self.of_object = None
self.params = [] # of form (type, name, default, nullok)
self.varargs = 0
self.deprecated = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'of-object':
self.of_object = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'return-type':
self.ret = arg[1]
elif arg[0] == 'caller-owns-return':
self.caller_owns_return = arg[1] in ('t', '#t')
elif arg[0] == 'unblock-threads':
self.unblock_threads = arg[1] in ('t', '#t')
elif arg[0] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
pdir = None
for farg in parg[2:]:
assert isinstance(farg, tuple)
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
elif farg[0] == 'direction':
pdir = farg[1]
self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir))
elif arg[0] == 'varargs':
self.varargs = arg[1] in ('t', '#t')
elif arg[0] == 'deprecated':
self.deprecated = arg[1]
else:
sys.stderr.write("Warning: %s argument unsupported.\n"
% (arg[0]))
dump = 1
if dump:
self.write_defs(sys.stderr)
if self.caller_owns_return is None and self.ret is not None:
self.guess_return_value_ownership()
def merge(self, old, parmerge):
self.caller_owns_return = old.caller_owns_return
self.varargs = old.varargs
# here we merge extra parameter flags accross to the new object.
if not parmerge:
self.params = copy.deepcopy(old.params)
return
for i in range(len(self.params)):
ptype, pname, pdflt, pnull = self.params[i]
for p2 in old.params:
if p2[1] == pname:
self.params[i] = (ptype, pname, p2[2], p2[3])
break
def _write_defs(self, fp=sys.stdout):
if self.of_object != (None, None):
fp.write(' (of-object "' + self.of_object + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.caller_owns_return:
fp.write(' (caller-owns-return #t)\n')
if self.unblock_threads:
fp.write(' (unblock_threads #t)\n')
if self.ret:
fp.write(' (return-type "' + self.ret + '")\n')
if self.deprecated:
fp.write(' (deprecated "' + self.deprecated + '")\n')
if self.params:
fp.write(' (parameters\n')
for ptype, pname, pdflt, pnull in self.params:
fp.write(' \'("' + ptype + '" "' + pname +'"')
if pdflt: fp.write(' (default "' + pdflt + '")')
if pnull: fp.write(' (null-ok)')
fp.write(')\n')
fp.write(' )\n')
if self.varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')
class MethodDef(MethodDefBase):
def __init__(self, name, *args):
MethodDefBase.__init__(self, name, *args)
for item in ('c_name', 'of_object'):
if self.__dict__[item] == None:
self.write_defs(sys.stderr)
raise RuntimeError, "definition missing required %s" % (item,)
def write_defs(self, fp=sys.stdout):
fp.write('(define-method ' + self.name + '\n')
self._write_defs(fp)
class VirtualDef(MethodDefBase):
def write_defs(self, fp=sys.stdout):
fp.write('(define-virtual ' + self.name + '\n')
self._write_defs(fp)
class FunctionDef(Definition):
def __init__(self, name, *args):
dump = 0
self.name = name
self.in_module = None
self.is_constructor_of = None
self.ret = None
self.caller_owns_return = None
self.unblock_threads = None
self.c_name = None
self.typecode = None
self.params = [] # of form (type, name, default, nullok)
self.varargs = 0
self.deprecated = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.in_module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'is-constructor-of':
self.is_constructor_of = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'return-type':
self.ret = arg[1]
elif arg[0] == 'caller-owns-return':
self.caller_owns_return = arg[1] in ('t', '#t')
elif arg[0] == 'unblock-threads':
self.unblock_threads = arg[1] in ('t', '#t')
elif arg[0] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
for farg in parg[2:]:
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
self.params.append(Parameter(ptype, pname, pdflt, pnull))
elif arg[0] == 'properties':
if self.is_constructor_of is None:
print >> sys.stderr, "Warning: (properties ...) "\
"is only valid for constructors"
for prop in arg[1:]:
pname = prop[0]
optional = False
argname = pname
for farg in prop[1:]:
if farg[0] == 'optional':
optional = True
elif farg[0] == 'argname':
argname = farg[1]
self.params.append(Property(pname, optional, argname))
elif arg[0] == 'varargs':
self.varargs = arg[1] in ('t', '#t')
elif arg[0] == 'deprecated':
self.deprecated = arg[1]
else:
sys.stderr.write("Warning: %s argument unsupported\n"
% (arg[0],))
dump = 1
if dump:
self.write_defs(sys.stderr)
if self.caller_owns_return is None and self.ret is not None:
self.guess_return_value_ownership()
for item in ('c_name',):
if self.__dict__[item] == None:
self.write_defs(sys.stderr)
raise RuntimeError, "definition missing required %s" % (item,)
_method_write_defs = MethodDef.__dict__['write_defs']
def merge(self, old, parmerge):
self.caller_owns_return = old.caller_owns_return
self.varargs = old.varargs
if not parmerge:
self.params = copy.deepcopy(old.params)
return
# here we merge extra parameter flags accross to the new object.
def merge_param(param):
for old_param in old.params:
if old_param.pname == param.pname:
if isinstance(old_param, Property):
# h2def never scans Property's, therefore if
# we have one it was manually written, so we
# keep it.
return copy.deepcopy(old_param)
else:
param.merge(old_param)
return param
raise RuntimeError, "could not find %s in old_parameters %r" % (
param.pname, [p.pname for p in old.params])
try:
self.params = map(merge_param, self.params)
except RuntimeError:
# parameter names changed and we can't find a match; it's
# safer to keep the old parameter list untouched.
self.params = copy.deepcopy(old.params)
if not self.is_constructor_of:
try:
self.is_constructor_of = old.is_constructor_of
except AttributeError:
pass
if isinstance(old, MethodDef):
self.name = old.name
# transmogrify from function into method ...
self.write_defs = self._method_write_defs
self.of_object = old.of_object
del self.params[0]
def write_defs(self, fp=sys.stdout):
fp.write('(define-function ' + self.name + '\n')
if self.in_module:
fp.write(' (in-module "' + self.in_module + '")\n')
if self.is_constructor_of:
fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.caller_owns_return:
fp.write(' (caller-owns-return #t)\n')
if self.unblock_threads:
fp.write(' (unblock-threads #t)\n')
if self.ret:
fp.write(' (return-type "' + self.ret + '")\n')
if self.deprecated:
fp.write(' (deprecated "' + self.deprecated + '")\n')
if self.params:
if isinstance(self.params[0], Parameter):
fp.write(' (parameters\n')
for ptype, pname, pdflt, pnull in self.params:
fp.write(' \'("' + ptype + '" "' + pname +'"')
if pdflt: fp.write(' (default "' + pdflt + '")')
if pnull: fp.write(' (null-ok)')
fp.write(')\n')
fp.write(' )\n')
elif isinstance(self.params[0], Property):
fp.write(' (properties\n')
for prop in self.params:
fp.write(' \'("' + prop.pname +'"')
if prop.optional: fp.write(' (optional)')
fp.write(')\n')
fp.write(' )\n')
else:
assert False, "strange parameter list %r" % self.params[0]
if self.varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')

View File

@ -0,0 +1,153 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import os, sys
import scmexpr
from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef
include_path = ['.']
class IncludeParser(scmexpr.Parser):
"""A simple parser that follows include statements automatically"""
def include(self, input_filename):
global include_path
if os.path.isabs(input_filename):
filename = input_filename
# set self.filename to the include name, to handle recursive includes
oldfile = self.filename
self.filename = filename
self.startParsing()
self.filename = oldfile
else:
inc_path = [os.path.dirname(self.filename)] + include_path
for filename in [os.path.join(path_entry, input_filename)
for path_entry in inc_path]:
if not os.path.exists(filename):
continue
# set self.filename to the include name, to handle recursive includes
oldfile = self.filename
self.filename = filename
self.startParsing()
self.filename = oldfile
break
else:
raise IOError("%s not found in include path %s" % (input_filename, inc_path))
class DefsParser(IncludeParser):
def __init__(self, arg, defines={}):
IncludeParser.__init__(self, arg)
self.objects = []
self.interfaces = []
self.enums = [] # enums and flags
self.boxes = [] # boxed types
self.pointers = [] # pointer types
self.functions = [] # functions and methods
self.virtuals = [] # virtual methods
self.c_name = {} # hash of c names of functions
self.methods = {} # hash of methods of particular objects
self.defines = defines # -Dfoo=bar options, as dictionary
def define_object(self, *args):
odef = apply(ObjectDef, args)
self.objects.append(odef)
self.c_name[odef.c_name] = odef
def define_interface(self, *args):
idef = apply(InterfaceDef, args)
self.interfaces.append(idef)
self.c_name[idef.c_name] = idef
def define_enum(self, *args):
edef = apply(EnumDef, args)
self.enums.append(edef)
self.c_name[edef.c_name] = edef
def define_flags(self, *args):
fdef = apply(FlagsDef, args)
self.enums.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_boxed(self, *args):
bdef = apply(BoxedDef, args)
self.boxes.append(bdef)
self.c_name[bdef.c_name] = bdef
def define_pointer(self, *args):
pdef = apply(PointerDef, args)
self.pointers.append(pdef)
self.c_name[pdef.c_name] = pdef
def define_function(self, *args):
fdef = apply(FunctionDef, args)
self.functions.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_method(self, *args):
mdef = apply(MethodDef, args)
self.functions.append(mdef)
self.c_name[mdef.c_name] = mdef
def define_virtual(self, *args):
vdef = apply(VirtualDef, args)
self.virtuals.append(vdef)
def merge(self, old, parmerge):
for obj in self.objects:
if old.c_name.has_key(obj.c_name):
obj.merge(old.c_name[obj.c_name])
for f in self.functions:
if old.c_name.has_key(f.c_name):
f.merge(old.c_name[f.c_name], parmerge)
def printMissing(self, old):
for obj in self.objects:
if not old.c_name.has_key(obj.c_name):
obj.write_defs()
for f in self.functions:
if not old.c_name.has_key(f.c_name):
f.write_defs()
def write_defs(self, fp=sys.stdout):
for obj in self.objects:
obj.write_defs(fp)
for enum in self.enums:
enum.write_defs(fp)
for boxed in self.boxes:
boxed.write_defs(fp)
for pointer in self.pointers:
pointer.write_defs(fp)
for func in self.functions:
func.write_defs(fp)
def find_object(self, c_name):
for obj in self.objects:
if obj.c_name == c_name:
return obj
else:
raise ValueError('object %r not found' % c_name)
def find_constructor(self, obj, overrides):
for func in self.functions:
if isinstance(func, FunctionDef) and \
func.is_constructor_of == obj.c_name and \
not overrides.is_ignored(func.c_name):
return func
def find_methods(self, obj):
objname = obj.c_name
return filter(lambda func, on=objname: isinstance(func, MethodDef) and
func.of_object == on, self.functions)
def find_virtuals(self, obj):
objname = obj.c_name
retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and
func.of_object == on, self.virtuals)
return retval
def find_functions(self):
return filter(lambda func: isinstance(func, FunctionDef) and
not func.is_constructor_of, self.functions)
def ifdef(self, *args):
if args[0] in self.defines:
for arg in args[1:]:
#print >> sys.stderr, "-----> Handling conditional definition (%s): %s" % (args[0], arg)
self.handle(arg)
else:
pass
#print >> sys.stderr, "-----> Conditional %s is not true" % (args[0],)
def ifndef(self, *args):
if args[0] not in self.defines:
for arg in args[1:]:
self.handle(arg)

View File

@ -0,0 +1,751 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys, os, string, re, getopt
import defsparser
import definitions
import override
import docextract
class Node:
def __init__(self, name, interfaces=[]):
self.name = name
self.interfaces = interfaces
self.subclasses = []
def add_child(self, node):
self.subclasses.append(node)
def build_object_tree(parser):
# reorder objects so that parent classes come first ...
objects = parser.objects[:]
pos = 0
while pos < len(objects):
parent = objects[pos].parent
for i in range(pos+1, len(objects)):
if objects[i].c_name == parent:
objects.insert(i+1, objects[pos])
del objects[pos]
break
else:
pos = pos + 1
root = Node(None)
nodes = { None: root }
for obj_def in objects:
parent_node = nodes[obj_def.parent]
node = Node(obj_def.c_name, obj_def.implements)
parent_node.add_child(node)
nodes[node.name] = node
if parser.interfaces:
interfaces = Node('gobject.GInterface')
root.add_child(interfaces)
nodes[interfaces.name] = interfaces
for obj_def in parser.interfaces:
node = Node(obj_def.c_name)
interfaces.add_child(node)
nodes[node.name] = node
if parser.boxes:
boxed = Node('gobject.GBoxed')
root.add_child(boxed)
nodes[boxed.name] = boxed
for obj_def in parser.boxes:
node = Node(obj_def.c_name)
boxed.add_child(node)
nodes[node.name] = node
if parser.pointers:
pointers = Node('gobject.GPointer')
root.add_child(pointers)
nodes[pointers.name] = pointers
for obj_def in parser.pointers:
node = Node(obj_def.c_name)
pointers.add_child(node)
nodes[node.name] = node
return root
class DocWriter:
def __init__(self):
# parse the defs file
self.parser = defsparser.DefsParser(())
self.overrides = override.Overrides()
self.classmap = {}
self.docs = {}
def add_sourcedirs(self, source_dirs):
self.docs = docextract.extract(source_dirs, self.docs)
def add_tmpldirs(self, tmpl_dirs):
self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs)
def add_docs(self, defs_file, overrides_file, module_name):
'''parse information about a given defs file'''
self.parser.filename = defs_file
self.parser.startParsing(defs_file)
if overrides_file:
self.overrides.handle_file(overrides_file)
for obj in self.parser.objects:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.interfaces:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.boxes:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.pointers:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
def pyname(self, name):
return self.classmap.get(name, name)
def __compare(self, obja, objb):
return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name))
def output_docs(self, output_prefix):
files = []
# class hierarchy
hierarchy = build_object_tree(self.parser)
filename = self.create_filename('hierarchy', output_prefix)
fp = open(filename, 'w')
self.write_full_hierarchy(hierarchy, fp)
fp.close()
obj_defs = self.parser.objects + self.parser.interfaces + \
self.parser.boxes + self.parser.pointers
obj_defs.sort(self.__compare)
for obj_def in obj_defs:
filename = self.create_filename(obj_def.c_name, output_prefix)
fp = open(filename, 'w')
if isinstance(obj_def, definitions.ObjectDef):
self.output_object_docs(obj_def, fp)
elif isinstance(obj_def, definitions.InterfaceDef):
self.output_interface_docs(obj_def, fp)
elif isinstance(obj_def, definitions.BoxedDef):
self.output_boxed_docs(obj_def, fp)
elif isinstance(obj_def, definitions.PointerDef):
self.output_boxed_docs(obj_def, fp)
fp.close()
files.append((os.path.basename(filename), obj_def))
if files:
filename = self.create_toc_filename(output_prefix)
fp = open(filename, 'w')
self.output_toc(files, fp)
fp.close()
def output_object_docs(self, obj_def, fp=sys.stdout):
self.write_class_header(obj_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(obj_def, fp)
self.close_section(fp)
# construct the inheritence hierarchy ...
ancestry = [ (obj_def.c_name, obj_def.implements) ]
try:
parent = obj_def.parent
while parent != None:
if parent == 'GObject':
ancestry.append(('GObject', []))
parent = None
else:
parent_def = self.parser.find_object(parent)
ancestry.append((parent_def.c_name, parent_def.implements))
parent = parent_def.parent
except ValueError:
pass
ancestry.reverse()
self.write_heading('Ancestry', fp)
self.write_hierarchy(obj_def.c_name, ancestry, fp)
self.close_section(fp)
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
self.write_heading('Constructor', fp)
self.write_constructor(constructor,
self.docs.get(constructor.c_name, None),
fp)
self.close_section(fp)
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(obj_def.c_name, fp)
def output_interface_docs(self, int_def, fp=sys.stdout):
self.write_class_header(int_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(int_def, fp)
self.close_section(fp)
methods = self.parser.find_methods(int_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(int_def.c_name, fp)
def output_boxed_docs(self, box_def, fp=sys.stdout):
self.write_class_header(box_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(box_def, fp)
self.close_section(fp)
constructor = self.parser.find_constructor(box_def, self.overrides)
if constructor:
self.write_heading('Constructor', fp)
self.write_constructor(constructor,
self.docs.get(constructor.c_name, None),
fp)
self.close_section(fp)
methods = self.parser.find_methods(box_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(box_def.c_name, fp)
def output_toc(self, files, fp=sys.stdout):
fp.write('TOC\n\n')
for filename, obj_def in files:
fp.write(obj_def.c_name + ' - ' + filename + '\n')
# override the following to create a more complex output format
def create_filename(self, obj_name, output_prefix):
'''Create output filename for this particular object'''
return output_prefix + '-' + string.lower(obj_name) + '.txt'
def create_toc_filename(self, output_prefix):
return self.create_filename(self, 'docs', output_prefix)
def write_full_hierarchy(self, hierarchy, fp):
def handle_node(node, fp, indent=''):
for child in node.subclasses:
fp.write(indent + node.name)
if node.interfaces:
fp.write(' (implements ')
fp.write(string.join(node.interfaces, ', '))
fp.write(')\n')
else:
fp.write('\n')
handle_node(child, fp, indent + ' ')
handle_node(hierarchy, fp)
# these need to handle default args ...
def create_constructor_prototype(self, func_def):
return func_def.is_constructor_of + '(' + \
string.join(map(lambda x: x[1], func_def.params), ', ') + \
')'
def create_function_prototype(self, func_def):
return func_def.name + '(' + \
string.join(map(lambda x: x[1], func_def.params), ', ') + \
')'
def create_method_prototype(self, meth_def):
return meth_def.of_object + '.' + \
meth_def.name + '(' + \
string.join(map(lambda x: x[1], meth_def.params), ', ') + \
')'
def write_class_header(self, obj_name, fp):
fp.write('Class %s\n' % obj_name)
fp.write('======%s\n\n' % ('=' * len(obj_name)))
def write_class_footer(self, obj_name, fp):
pass
def write_heading(self, text, fp):
fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
def close_section(self, fp):
pass
def write_synopsis(self, obj_def, fp):
fp.write('class %s' % obj_def.c_name)
if isinstance(obj_def, definitions.ObjectDef):
bases = []
if obj_def.parent: bases.append(obj_def.parent)
bases = bases = obj_def.implements
if bases:
fp.write('(%s)' % string.join(bases, ', '))
fp.write(':\n')
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
prototype = self.create_constructor_prototype(constructor)
fp.write(' def %s\n' % prototype)
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
for meth in methods:
prototype = self.create_method_prototype(meth)
fp.write(' def %s\n' % prototype)
def write_hierarchy(self, obj_name, ancestry, fp):
indent = ''
for name, interfaces in ancestry:
fp.write(indent + '+-- ' + name)
if interfaces:
fp.write(' (implements ')
fp.write(string.join(interfaces, ', '))
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
fp.write('\n')
def write_constructor(self, func_def, func_doc, fp):
prototype = self.create_constructor_prototype(func_def)
fp.write(prototype + '\n\n')
for type, name, dflt, null in func_def.params:
if func_doc:
descr = func_doc.get_param_description(name)
else:
descr = 'a ' + type
fp.write(' ' + name + ': ' + descr + '\n')
if func_def.ret and func_def.ret != 'none':
if func_doc and func_doc.ret:
descr = func_doc.ret
else:
descr = 'a ' + func_def.ret
fp.write(' Returns: ' + descr + '\n')
if func_doc and func_doc.description:
fp.write(func_doc.description)
fp.write('\n\n\n')
def write_method(self, meth_def, func_doc, fp):
prototype = self.create_method_prototype(meth_def)
fp.write(prototype + '\n\n')
for type, name, dflt, null in meth_def.params:
if func_doc:
descr = func_doc.get_param_description(name)
else:
descr = 'a ' + type
fp.write(' ' + name + ': ' + descr + '\n')
if meth_def.ret and meth_def.ret != 'none':
if func_doc and func_doc.ret:
descr = func_doc.ret
else:
descr = 'a ' + meth_def.ret
fp.write(' Returns: ' + descr + '\n')
if func_doc and func_doc.description:
fp.write('\n')
fp.write(func_doc.description)
fp.write('\n\n')
class DocbookDocWriter(DocWriter):
def __init__(self, use_xml=0):
DocWriter.__init__(self)
self.use_xml = use_xml
def create_filename(self, obj_name, output_prefix):
'''Create output filename for this particular object'''
stem = output_prefix + '-' + string.lower(obj_name)
if self.use_xml:
return stem + '.xml'
else:
return stem + '.sgml'
def create_toc_filename(self, output_prefix):
if self.use_xml:
return self.create_filename('classes', output_prefix)
else:
return self.create_filename('docs', output_prefix)
# make string -> reference translation func
__transtable = [ '-' ] * 256
for digit in '0123456789':
__transtable[ord(digit)] = digit
for letter in 'abcdefghijklmnopqrstuvwxyz':
__transtable[ord(letter)] = letter
__transtable[ord(string.upper(letter))] = letter
__transtable = string.join(__transtable, '')
def make_class_ref(self, obj_name):
return 'class-' + string.translate(obj_name, self.__transtable)
def make_method_ref(self, meth_def):
return 'method-' + string.translate(meth_def.of_object,
self.__transtable) + \
'--' + string.translate(meth_def.name, self.__transtable)
__function_pat = re.compile(r'(\w+)\s*\(\)')
def __format_function(self, match):
info = self.parser.c_name.get(match.group(1), None)
if info:
if isinstance(info, defsparser.FunctionDef):
if info.is_constructor_of is not None:
# should have a link here
return '<function>%s()</function>' % \
self.pyname(info.is_constructor_of)
else:
return '<function>' + info.name + '()</function>'
if isinstance(info, defsparser.MethodDef):
return '<link linkend="' + self.make_method_ref(info) + \
'"><function>' + self.pyname(info.of_object) + '.' + \
info.name + '()</function></link>'
# fall through through
return '<function>' + match.group(1) + '()</function>'
__parameter_pat = re.compile(r'\@(\w+)')
def __format_param(self, match):
return '<parameter>' + match.group(1) + '</parameter>'
__constant_pat = re.compile(r'\%(-?\w+)')
def __format_const(self, match):
return '<literal>' + match.group(1) + '</literal>'
__symbol_pat = re.compile(r'#([\w-]+)')
def __format_symbol(self, match):
info = self.parser.c_name.get(match.group(1), None)
if info:
if isinstance(info, defsparser.FunctionDef):
if info.is_constructor_of is not None:
# should have a link here
return '<methodname>' + self.pyname(info.is_constructor_of) + \
'</methodname>'
else:
return '<function>' + info.name + '</function>'
if isinstance(info, defsparser.MethodDef):
return '<link linkend="' + self.make_method_ref(info) + \
'"><methodname>' + self.pyname(info.of_object) + '.' + \
info.name + '</methodname></link>'
if isinstance(info, defsparser.ObjectDef) or \
isinstance(info, defsparser.InterfaceDef) or \
isinstance(info, defsparser.BoxedDef) or \
isinstance(info, defsparser.PointerDef):
return '<link linkend="' + self.make_class_ref(info.c_name) + \
'"><classname>' + self.pyname(info.c_name) + \
'</classname></link>'
# fall through through
return '<literal>' + match.group(1) + '</literal>'
def reformat_text(self, text, singleline=0):
# replace special strings ...
text = self.__function_pat.sub(self.__format_function, text)
text = self.__parameter_pat.sub(self.__format_param, text)
text = self.__constant_pat.sub(self.__format_const, text)
text = self.__symbol_pat.sub(self.__format_symbol, text)
# don't bother with <para> expansion for single line text.
if singleline: return text
lines = string.split(string.strip(text), '\n')
for index in range(len(lines)):
if string.strip(lines[index]) == '':
lines[index] = '</para>\n<para>'
continue
lines.insert(0, '<para>')
lines.append('</para>')
return string.join(lines, '\n')
# write out hierarchy
def write_full_hierarchy(self, hierarchy, fp):
def handle_node(node, fp, indent=''):
if node.name:
fp.write('%s<link linkend="%s">%s</link>' %
(indent, self.make_class_ref(node.name),
self.pyname(node.name)))
if node.interfaces:
fp.write(' (implements ')
for i in range(len(node.interfaces)):
fp.write('<link linkend="%s">%s</link>' %
(self.make_class_ref(node.interfaces[i]),
self.pyname(node.interfaces[i])))
if i != len(node.interfaces) - 1:
fp.write(', ')
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
node.subclasses.sort(lambda a,b:
cmp(self.pyname(a.name), self.pyname(b.name)))
for child in node.subclasses:
handle_node(child, fp, indent)
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
fp.write('<synopsis>')
handle_node(hierarchy, fp)
fp.write('</synopsis>\n')
# these need to handle default args ...
def create_constructor_prototype(self, func_def):
sgml = [ '<constructorsynopsis language="python">\n']
sgml.append(' <methodname>__init__</methodname>\n')
for type, name, dflt, null in func_def.params:
sgml.append(' <methodparam><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</methodparam>\n')
if not func_def.params:
sgml.append(' <methodparam></methodparam>')
sgml.append(' </constructorsynopsis>')
return string.join(sgml, '')
def create_function_prototype(self, func_def):
sgml = [ '<funcsynopsis language="python">\n <funcprototype>\n']
sgml.append(' <funcdef><function>')
sgml.append(func_def.name)
sgml.append('</function></funcdef>\n')
for type, name, dflt, null in func_def.params:
sgml.append(' <paramdef><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</paramdef>\n')
if not func_def.params:
sgml.append(' <paramdef></paramdef')
sgml.append(' </funcprototype>\n </funcsynopsis>')
return string.join(sgml, '')
def create_method_prototype(self, meth_def, addlink=0):
sgml = [ '<methodsynopsis language="python">\n']
sgml.append(' <methodname>')
if addlink:
sgml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
sgml.append(self.pyname(meth_def.name))
if addlink:
sgml.append('</link>')
sgml.append('</methodname>\n')
for type, name, dflt, null in meth_def.params:
sgml.append(' <methodparam><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</methodparam>\n')
if not meth_def.params:
sgml.append(' <methodparam></methodparam>')
sgml.append(' </methodsynopsis>')
return string.join(sgml, '')
def write_class_header(self, obj_name, fp):
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
fp.write('<refentry id="' + self.make_class_ref(obj_name) + '">\n')
fp.write(' <refmeta>\n')
fp.write(' <refentrytitle>%s</refentrytitle>\n'
% self.pyname(obj_name))
fp.write(' <manvolnum>3</manvolnum>\n')
fp.write(' <refmiscinfo>PyGTK Docs</refmiscinfo>\n')
fp.write(' </refmeta>\n\n')
fp.write(' <refnamediv>\n')
fp.write(' <refname>%s</refname><refpurpose></refpurpose>\n'
% self.pyname(obj_name))
fp.write(' </refnamediv>\n\n')
def write_class_footer(self, obj_name, fp):
fp.write('</refentry>\n')
def write_heading(self, text, fp):
fp.write(' <refsect1>\n')
fp.write(' <title>' + text + '</title>\n\n')
def close_section(self, fp):
fp.write(' </refsect1>\n')
def write_synopsis(self, obj_def, fp):
fp.write('<classsynopsis language="python">\n')
fp.write(' <ooclass><classname>%s</classname></ooclass>\n'
% self.pyname(obj_def.c_name))
if isinstance(obj_def, definitions.ObjectDef):
if obj_def.parent:
fp.write(' <ooclass><classname><link linkend="%s">%s'
'</link></classname></ooclass>\n'
% (self.make_class_ref(obj_def.parent),
self.pyname(obj_def.parent)))
for base in obj_def.implements:
fp.write(' <ooclass><classname><link linkend="%s">%s'
'</link></classname></ooclass>\n'
% (self.make_class_ref(base), self.pyname(base)))
elif isinstance(obj_def, definitions.InterfaceDef):
fp.write(' <ooclass><classname>gobject.GInterface'
'</classname></ooclass>\n')
elif isinstance(obj_def, definitions.BoxedDef):
fp.write(' <ooclass><classname>gobject.GBoxed'
'</classname></ooclass>\n')
elif isinstance(obj_def, definitions.PointerDef):
fp.write(' <ooclass><classname>gobject.GPointer'
'</classname></ooclass>\n')
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
fp.write('%s\n' % self.create_constructor_prototype(constructor))
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
for meth in methods:
fp.write('%s\n' % self.create_method_prototype(meth, addlink=1))
fp.write('</classsynopsis>\n\n')
def write_hierarchy(self, obj_name, ancestry, fp):
fp.write('<synopsis>')
indent = ''
for name, interfaces in ancestry:
fp.write(indent + '+-- <link linkend="' +
self.make_class_ref(name) + '">'+ self.pyname(name) + '</link>')
if interfaces:
fp.write(' (implements ')
for i in range(len(interfaces)):
fp.write('<link linkend="%s">%s</link>' %
(self.make_class_ref(interfaces[i]),
self.pyname(interfaces[i])))
if i != len(interfaces) - 1:
fp.write(', ')
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
fp.write('</synopsis>\n\n')
def write_params(self, params, ret, func_doc, fp):
if not params and (not ret or ret == 'none'):
return
fp.write(' <variablelist>\n')
for type, name, dflt, null in params:
if func_doc:
descr = string.strip(func_doc.get_param_description(name))
else:
descr = 'a ' + type
fp.write(' <varlistentry>\n')
fp.write(' <term><parameter>%s</parameter>&nbsp;:</term>\n' % name)
fp.write(' <listitem><simpara>%s</simpara></listitem>\n' %
self.reformat_text(descr, singleline=1))
fp.write(' </varlistentry>\n')
if ret and ret != 'none':
if func_doc and func_doc.ret:
descr = string.strip(func_doc.ret)
else:
descr = 'a ' + ret
fp.write(' <varlistentry>\n')
fp.write(' <term><emphasis>Returns</emphasis>&nbsp;:</term>\n')
fp.write(' <listitem><simpara>%s</simpara></listitem>\n' %
self.reformat_text(descr, singleline=1))
fp.write(' </varlistentry>\n')
fp.write(' </variablelist>\n')
def write_constructor(self, func_def, func_doc, fp):
prototype = self.create_constructor_prototype(func_def)
fp.write('<programlisting>%s</programlisting>\n' % prototype)
self.write_params(func_def.params, func_def.ret, func_doc, fp)
if func_doc and func_doc.description:
fp.write(self.reformat_text(func_doc.description))
fp.write('\n\n\n')
def write_method(self, meth_def, func_doc, fp):
fp.write(' <refsect2 id="' + self.make_method_ref(meth_def) + '">\n')
fp.write(' <title>' + self.pyname(meth_def.of_object) + '.' +
meth_def.name + '</title>\n\n')
prototype = self.create_method_prototype(meth_def)
fp.write('<programlisting>%s</programlisting>\n' % prototype)
self.write_params(meth_def.params, meth_def.ret, func_doc, fp)
if func_doc and func_doc.description:
fp.write(self.reformat_text(func_doc.description))
fp.write(' </refsect2>\n\n\n')
def output_toc(self, files, fp=sys.stdout):
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
#for filename, obj_def in files:
# fp.write(' <!ENTITY ' + string.translate(obj_def.c_name,
# self.__transtable) +
# ' SYSTEM "' + filename + '" >\n')
#fp.write(']>\n\n')
#fp.write('<reference id="class-reference">\n')
#fp.write(' <title>Class Documentation</title>\n')
#for filename, obj_def in files:
# fp.write('&' + string.translate(obj_def.c_name,
# self.__transtable) + ';\n')
#fp.write('</reference>\n')
fp.write('<reference id="class-reference" xmlns:xi="http://www.w3.org/2001/XInclude">\n')
fp.write(' <title>Class Reference</title>\n')
for filename, obj_def in files:
fp.write(' <xi:include href="%s"/>\n' % filename)
fp.write('</reference>\n')
else:
fp.write('<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1.2//EN" [\n')
for filename, obj_def in files:
fp.write(' <!ENTITY ' + string.translate(obj_def.c_name,
self.__transtable) +
' SYSTEM "' + filename + '" >\n')
fp.write(']>\n\n')
fp.write('<book id="index">\n\n')
fp.write(' <bookinfo>\n')
fp.write(' <title>PyGTK Docs</title>\n')
fp.write(' <authorgroup>\n')
fp.write(' <author>\n')
fp.write(' <firstname>James</firstname>\n')
fp.write(' <surname>Henstridge</surname>\n')
fp.write(' </author>\n')
fp.write(' </authorgroup>\n')
fp.write(' </bookinfo>\n\n')
fp.write(' <chapter id="class-hierarchy">\n')
fp.write(' <title>Class Hierarchy</title>\n')
fp.write(' <para>Not done yet</para>\n')
fp.write(' </chapter>\n\n')
fp.write(' <reference id="class-reference">\n')
fp.write(' <title>Class Documentation</title>\n')
for filename, obj_def in files:
fp.write('&' + string.translate(obj_def.c_name,
self.__transtable) + ';\n')
fp.write(' </reference>\n')
fp.write('</book>\n')
if __name__ == '__main__':
try:
opts, args = getopt.getopt(sys.argv[1:], "d:s:o:",
["defs-file=", "override=", "source-dir=",
"output-prefix="])
except getopt.error, e:
sys.stderr.write('docgen.py: %s\n' % e)
sys.stderr.write(
'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
sys.exit(1)
defs_file = None
overrides_file = None
source_dirs = []
output_prefix = 'docs'
for opt, arg in opts:
if opt in ('-d', '--defs-file'):
defs_file = arg
if opt in ('--override',):
overrides_file = arg
elif opt in ('-s', '--source-dir'):
source_dirs.append(arg)
elif opt in ('-o', '--output-prefix'):
output_prefix = arg
if len(args) != 0 or not defs_file:
sys.stderr.write(
'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
sys.exit(1)
d = DocbookDocWriter()
d.add_sourcedirs(source_dirs)
d.add_docs(defs_file, overrides_file, 'gtk')
d.output_docs(output_prefix)

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import optparse
import defsparser
parser = optparse.OptionParser(
usage="usage: %prog [options] generated-defs old-defs")
parser.add_option("-p", "--merge-parameters",
help="Merge changes in function/methods parameter lists",
action="store_true", dest="parmerge", default=False)
(options, args) = parser.parse_args()
if len(args) != 2:
parser.error("wrong number of arguments")
newp = defsparser.DefsParser(args[0])
oldp = defsparser.DefsParser(args[1])
newp.startParsing()
oldp.startParsing()
newp.merge(oldp, options.parmerge)
newp.write_defs()

89
moo/moopython/codegen/mkskel.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys, os, getopt
module_init_template = \
'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
'#ifdef HAVE_CONFIG_H\n' + \
'# include "config.h"\n' + \
'#endif\n' + \
'#include <Python.h>\n' + \
'#include <pygtk.h>\n' + \
'\n' + \
'/* include any extra headers needed here */\n' + \
'\n' + \
'void %(prefix)s_register_classes(PyObject *d);\n' + \
'extern PyMethodDef %(prefix)s_functions[];\n' + \
'\n' + \
'DL_EXPORT(void)\n' + \
'init%(module)s(void)\n' + \
'{\n' + \
' PyObject *m, *d;\n' + \
'\n' + \
' /* perform any initialisation required by the library here */\n' + \
'\n' + \
' m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \
' d = PyModule_GetDict(m);\n' + \
'\n' + \
' init_pygtk();\n' + \
'\n' + \
' %(prefix)s_register_classes(d);\n' + \
'\n' + \
' /* add anything else to the module dictionary (such as constants) */\n' +\
'\n' + \
' if (PyErr_Occurred())\n' + \
' Py_FatalError("could not initialise module %(module)s");\n' + \
'}\n'
override_template = \
'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
'%%%%\n' + \
'headers\n' + \
'/* include any required headers here */\n' + \
'%%%%\n' + \
'init\n' + \
' /* include any code here that needs to be executed before the\n' + \
' * extension classes get initialised */\n' + \
'%%%%\n' + \
'\n' + \
'/* you should add appropriate ignore, ignore-glob and\n' + \
' * override sections here */\n'
def open_with_backup(file):
if os.path.exists(file):
try:
os.rename(file, file+'~')
except OSError:
# fail silently if we can't make a backup
pass
return open(file, 'w')
def write_skels(fileprefix, prefix, module):
fp = open_with_backup(fileprefix+'module.c')
fp.write(module_init_template % { 'prefix': prefix, 'module': module })
fp.close()
fp = open_with_backup(fileprefix+'.override')
fp.write(override_template % { 'prefix': prefix, 'module': module })
fp.close()
if __name__ == '__main__':
opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h',
['file-prefix=', 'prefix=', 'module=', 'help'])
fileprefix = None
prefix = None
module = None
for opt, arg in opts:
if opt in ('-f', '--file-prefix'):
fileprefix = arg
elif opt in ('-p', '--prefix'):
prefix = arg
elif opt in ('-m', '--module'):
module = arg
elif opt in ('-h', '--help'):
print 'usage: mkskel.py -f fileprefix -p prefix -m module'
sys.exit(0)
if not fileprefix or not prefix or not module:
print 'usage: mkskel.py -f fileprefix -p prefix -m module'
sys.exit(1)
write_skels(fileprefix, prefix, module)

View File

@ -0,0 +1,281 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# this file contains code for loading up an override file. The override file
# provides implementations of functions where the code generator could not
# do its job correctly.
import fnmatch
import os
import re
import string
import sys
def class2cname(klass, method):
c_name = ''
for c in klass:
if c.isupper():
c_name += '_' + c.lower()
else:
c_name += c
return c_name[1:] + '_' + method
import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)')
class Overrides:
def __init__(self, filename=None):
self.modulename = None
self.ignores = {}
self.glob_ignores = []
self.type_ignores = {}
self.overrides = {}
self.overridden = {}
self.kwargs = {}
self.noargs = {}
self.onearg = {}
self.staticmethod = {}
self.classmethod = {}
self.startlines = {}
self.override_attrs = {}
self.override_slots = {}
self.headers = ''
self.body = ''
self.init = ''
self.imports = []
self.defines = {}
self.functions = {}
self.newstyle_constructors = {}
self.dynamicnamespace = False
if filename:
self.handle_file(filename)
def handle_file(self, filename):
oldpath = os.getcwd()
fp = open(filename, 'r')
dirname = os.path.dirname(os.path.abspath(filename))
if dirname != oldpath:
os.chdir(dirname)
# read all the components of the file ...
bufs = []
startline = 1
lines = []
line = fp.readline()
linenum = 1
while line:
if line == '%%\n' or line == '%%':
if lines:
bufs.append((string.join(lines, ''), startline))
startline = linenum + 1
lines = []
else:
lines.append(line)
line = fp.readline()
linenum = linenum + 1
if lines:
bufs.append((string.join(lines, ''), startline))
if not bufs: return
for buf, startline in bufs:
self.__parse_override(buf, startline, filename)
os.chdir(oldpath)
def __parse_override(self, buffer, startline, filename):
pos = string.find(buffer, '\n')
if pos >= 0:
line = buffer[:pos]
rest = buffer[pos+1:]
else:
line = buffer ; rest = ''
words = string.split(line)
command = words[0]
if (command == 'ignore' or
command == 'ignore-' + sys.platform):
"ignore/ignore-platform [functions..]"
for func in words[1:]:
self.ignores[func] = 1
for func in string.split(rest):
self.ignores[func] = 1
elif (command == 'ignore-glob' or
command == 'ignore-glob-' + sys.platform):
"ignore-glob/ignore-glob-platform [globs..]"
for func in words[1:]:
self.glob_ignores.append(func)
for func in string.split(rest):
self.glob_ignores.append(func)
elif (command == 'ignore-type' or
command == 'ignore-type-' + sys.platform):
"ignore-type/ignore-type-platform [typenames..]"
for typename in words[1:]:
self.type_ignores[typename] = 1
for typename in string.split(rest):
self.type_ignores[typename] = 1
elif command == 'override':
"override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]"
func = words[1]
if 'kwargs' in words[1:]:
self.kwargs[func] = 1
elif 'noargs' in words[1:]:
self.noargs[func] = 1
elif 'onearg' in words[1:]:
self.onearg[func] = True
if 'staticmethod' in words[1:]:
self.staticmethod[func] = True
elif 'classmethod' in words[1:]:
self.classmethod[func] = True
if func in self.overrides:
raise RuntimeError("Function %s is being overridden more than once" % (func,))
self.overrides[func] = rest
self.startlines[func] = (startline + 1, filename)
elif command == 'override-attr':
"override-slot Class.attr"
attr = words[1]
self.override_attrs[attr] = rest
self.startlines[attr] = (startline + 1, filename)
elif command == 'override-slot':
"override-slot Class.slot"
slot = words[1]
self.override_slots[slot] = rest
self.startlines[slot] = (startline + 1, filename)
elif command == 'headers':
"headers"
self.headers = '%s\n#line %d "%s"\n%s' % \
(self.headers, startline + 1, filename, rest)
elif command == 'body':
"body"
self.body = '%s\n#line %d "%s"\n%s' % \
(self.body, startline + 1, filename, rest)
elif command == 'init':
"init"
self.init = '%s\n#line %d "%s"\n%s' % \
(self.init, startline + 1, filename, rest)
elif command == 'modulename':
"modulename name"
self.modulename = words[1]
elif command == 'include':
"include filename"
for filename in words[1:]:
self.handle_file(filename)
for filename in string.split(rest):
self.handle_file(filename)
elif command == 'import':
"import module1 [\n module2, \n module3 ...]"
for line in string.split(buffer, '\n'):
match = import_pat.match(line)
if match:
self.imports.append(match.groups())
elif command == 'define':
"define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]"
"define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]"
func = words[1]
klass = None
if func.find('.') != -1:
klass, func = func.split('.', 1)
if not self.defines.has_key(klass):
self.defines[klass] = {}
self.defines[klass][func] = rest
else:
self.functions[func] = rest
if 'kwargs' in words[1:]:
self.kwargs[func] = 1
elif 'noargs' in words[1:]:
self.noargs[func] = 1
elif 'onearg' in words[1:]:
self.onearg[func] = 1
if 'staticmethod' in words[1:]:
self.staticmethod[func] = True
elif 'classmethod' in words[1:]:
self.classmethod[func] = True
self.startlines[func] = (startline + 1, filename)
elif command == 'new-constructor':
"new-constructor GType"
gtype, = words[1:]
self.newstyle_constructors[gtype] = True
elif command == 'options':
for option in words[1:]:
if option == 'dynamicnamespace':
self.dynamicnamespace = True
def is_ignored(self, name):
if self.ignores.has_key(name):
return 1
for glob in self.glob_ignores:
if fnmatch.fnmatchcase(name, glob):
return 1
return 0
def is_type_ignored(self, name):
return name in self.type_ignores
def is_overriden(self, name):
return self.overrides.has_key(name)
def is_already_included(self, name):
return self.overridden.has_key(name)
def override(self, name):
self.overridden[name] = 1
return self.overrides[name]
def define(self, klass, name):
self.overridden[class2cname(klass, name)] = 1
return self.defines[klass][name]
def function(self, name):
return self.functions[name]
def getstartline(self, name):
return self.startlines[name]
def wants_kwargs(self, name):
return self.kwargs.has_key(name)
def wants_noargs(self, name):
return self.noargs.has_key(name)
def wants_onearg(self, name):
return self.onearg.has_key(name)
def is_staticmethod(self, name):
return self.staticmethod.has_key(name)
def is_classmethod(self, name):
return self.classmethod.has_key(name)
def attr_is_overriden(self, attr):
return self.override_attrs.has_key(attr)
def attr_override(self, attr):
return self.override_attrs[attr]
def slot_is_overriden(self, slot):
return self.override_slots.has_key(slot)
def slot_override(self, slot):
return self.override_slots[slot]
def get_headers(self):
return self.headers
def get_body(self):
return self.body
def get_init(self):
return self.init
def get_imports(self):
return self.imports
def get_defines_for(self, klass):
return self.defines.get(klass, {})
def get_functions(self):
return self.functions

View File

@ -0,0 +1,867 @@
### -*- python -*-
### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
import argtypes
import os
DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ)
def join_ctype_name(ctype, name):
'''Joins a C type and a variable name into a single string'''
if ctype[-1] != '*':
return " ".join((ctype, name))
else:
return "".join((ctype, name))
class CodeSink(object):
def __init__(self):
self.indent_level = 0 # current indent level
self.indent_stack = [] # previous indent levels
def _format_code(self, code):
assert isinstance(code, str)
l = []
for line in code.split('\n'):
l.append(' '*self.indent_level + line)
if l[-1]:
l.append('')
return '\n'.join(l)
def writeln(self, line=''):
raise NotImplementedError
def indent(self, level=4):
'''Add a certain ammount of indentation to all lines written
from now on and until unindent() is called'''
self.indent_stack.append(self.indent_level)
self.indent_level += level
def unindent(self):
'''Revert indentation level to the value before last indent() call'''
self.indent_level = self.indent_stack.pop()
class FileCodeSink(CodeSink):
def __init__(self, fp):
CodeSink.__init__(self)
assert isinstance(fp, file)
self.fp = fp
def writeln(self, line=''):
self.fp.write(self._format_code(line))
class MemoryCodeSink(CodeSink):
def __init__(self):
CodeSink.__init__(self)
self.lines = []
def writeln(self, line=''):
self.lines.append(self._format_code(line))
def flush_to(self, sink):
assert isinstance(sink, CodeSink)
for line in self.lines:
sink.writeln(line.rstrip())
self.lines = []
def flush(self):
l = []
for line in self.lines:
l.append(self._format_code(line))
self.lines = []
return "".join(l)
class ReverseWrapper(object):
'''Object that generates a C->Python wrapper'''
def __init__(self, cname, is_static=True):
assert isinstance(cname, str)
self.cname = cname
## function object we will call, or object whose method we will call
self.called_pyobj = None
## name of method of self.called_pyobj we will call
self.method_name = None
self.is_static = is_static
self.parameters = []
self.declarations = MemoryCodeSink()
self.post_return_code = MemoryCodeSink()
self.body = MemoryCodeSink()
self.check_exception_code = MemoryCodeSink()
self.cleanup_actions = []
self.pyargv_items = []
self.pyargv_optional_items = []
self.pyret_parse_items = [] # list of (format_spec, parameter)
def set_call_target(self, called_pyobj, method_name=None):
assert called_pyobj is not None
assert self.called_pyobj is None
self.called_pyobj = called_pyobj
self.method_name = method_name
def set_return_type(self, return_type):
assert isinstance(return_type, ReturnType)
self.return_type = return_type
def add_parameter(self, param):
assert isinstance(param, Parameter)
self.parameters.append(param)
def add_declaration(self, decl_code):
self.declarations.writeln(decl_code)
def add_pyargv_item(self, variable, optional=False):
if optional:
self.pyargv_optional_items.append(variable)
else:
self.pyargv_items.append(variable)
def add_pyret_parse_item(self, format_specifier, parameter, prepend=False):
if prepend:
self.pyret_parse_items.insert(0, (format_specifier, parameter))
else:
self.pyret_parse_items.append((format_specifier, parameter))
def write_code(self, code,
cleanup=None,
failure_expression=None,
failure_cleanup=None,
failure_exception=None,
code_sink=None):
'''Add a chunk of code with cleanup and error handling
This method is to be used by TypeHandlers when generating code
Keywork arguments:
code -- code to add
cleanup -- code to cleanup any dynamic resources created by @code
(except in case of failure) (default None)
failure_expression -- C boolean expression to indicate
if anything failed (default None)
failure_cleanup -- code to cleanup any dynamic resources
created by @code in case of failure (default None)
failure_exception -- code to raise an exception in case of
failure (which will be immediately
printed and cleared), (default None)
code_sink -- "code sink" to use; by default,
ReverseWrapper.body is used, which writes the
main body of the wrapper, before calling the
python method. Alternatively,
ReverseWrapper.after_pyret_parse can be used, to
write code after the PyArg_ParseTuple that
parses the python method return value.
'''
if code_sink is None:
code_sink = self.body
if code is not None:
code_sink.writeln(code)
if failure_expression is not None:
code_sink.writeln("if (%s) {" % (failure_expression,))
code_sink.indent()
if failure_exception is None:
code_sink.writeln("if (PyErr_Occurred())")
code_sink.indent()
code_sink.writeln("PyErr_Print();")
code_sink.unindent()
else:
code_sink.writeln(failure_exception)
code_sink.writeln("PyErr_Print();")
if failure_cleanup is not None:
code_sink.writeln(failure_cleanup)
for cleanup_action in self.cleanup_actions:
code_sink.writeln(cleanup_action)
self.return_type.write_error_return()
code_sink.unindent()
code_sink.writeln("}")
if cleanup is not None:
self.cleanup_actions.insert(0, cleanup)
def generate(self, sink):
'''Generate the code into a CodeSink object'''
assert isinstance(sink, CodeSink)
if DEBUG_MODE:
self.declarations.writeln("/* begin declarations */")
self.body.writeln("/* begin main body */")
self.post_return_code.writeln("/* begin post-return code */")
self.add_declaration("PyGILState_STATE __py_state;")
self.write_code(code="__py_state = pyg_gil_state_ensure();",
cleanup="pyg_gil_state_release(__py_state);")
for param in self.parameters:
param.convert_c2py()
assert self.called_pyobj is not None,\
"Parameters failed to provide a target function or method."
if self.is_static:
sink.writeln('static %s' % self.return_type.get_c_type())
else:
sink.writeln(self.return_type.get_c_type())
c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
self.return_type.write_decl()
self.add_declaration("PyObject *py_retval;")
## Handle number of arguments
if self.pyargv_items:
self.add_declaration("PyObject *py_args;")
py_args = "py_args"
if self.pyargv_optional_items:
self.add_declaration("int argc = %i;" % len(self.pyargv_items))
argc = "argc"
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s)" % arg)
self.body.indent()
self.body.writeln("++argc;")
self.body.unindent()
else:
argc = str(len(self.pyargv_items))
else:
if self.pyargv_optional_items:
self.add_declaration("PyObject *py_args;")
py_args = "py_args"
self.add_declaration("int argc = 0;")
argc = "argc"
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s)" % arg)
self.body.indent()
self.body.writeln("++argc;")
self.body.unindent()
else:
py_args = "NULL"
argc = None
self.body.writeln()
if py_args != "NULL":
self.write_code("py_args = PyTuple_New(%s);" % argc,
cleanup="Py_DECREF(py_args);")
pos = 0
for arg in self.pyargv_items:
try: # try to remove the Py_DECREF cleanup action, if we can
self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
except ValueError: # otherwise we have to Py_INCREF..
self.body.writeln("Py_INCREF(%s);" % arg)
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
pos += 1
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s) {" % arg)
self.body.indent()
try: # try to remove the Py_DECREF cleanup action, if we can
self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
except ValueError: # otherwise we have to Py_INCREF..
self.body.writeln("Py_INCREF(%s);" % arg)
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
self.body.unindent()
self.body.writeln("}")
pos += 1
self.body.writeln()
## Call the python method
if self.method_name is None:
self.write_code("py_retval = PyObject_Call(%s, %s);"
% (self.called_pyobj, py_args),
cleanup="Py_XDECREF(py_retval);")
self.check_exception_code.flush_to(self.body)
self.write_code(None, failure_expression="!py_retval")
else:
self.add_declaration("PyObject *py_method;")
self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
% (self.called_pyobj, self.method_name),
cleanup="Py_DECREF(py_method);",
failure_expression="!py_method")
self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
% (py_args,),
cleanup="Py_XDECREF(py_retval);")
self.check_exception_code.flush_to(self.body)
self.write_code(None, failure_expression="!py_retval")
## -- Handle the return value --
## we need to check if the return_type object is prepared to cooperate with multiple return values
len_before = len(self.pyret_parse_items)
self.return_type.write_conversion()
len_after = len(self.pyret_parse_items)
assert (self.return_type.get_c_type() == 'void'
or not (len_before == len_after and len_after > 0)),\
("Bug in reverse wrappers: return type handler %s"
" is not prepared to cooperate multiple return values") % (type(self.return_type),)
sink.indent()
if self.pyret_parse_items == [("", "")]:
## special case when there are no return parameters
self.write_code(
code=None,
failure_expression='py_retval != Py_None',
failure_exception=('PyErr_SetString(PyExc_TypeError, '
'"virtual method should return None");'))
else:
if len(self.pyret_parse_items) == 1:
## if retval is one item only, pack it in a tuple so we
## can use PyArg_ParseTuple as usual..
self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
if len(self.pyret_parse_items) > 0:
## Parse return values using PyArg_ParseTuple
params = ["py_retval",
'"%s"' % "".join([format for format, param in self.pyret_parse_items])]
params.extend([param for format, param in self.pyret_parse_items if param])
self.write_code(code=None, failure_expression=(
'!PyArg_ParseTuple(%s)' % (', '.join(params),)))
if DEBUG_MODE:
self.declarations.writeln("/* end declarations */")
self.declarations.flush_to(sink)
sink.writeln()
if DEBUG_MODE:
self.body.writeln("/* end main body */")
self.body.flush_to(sink)
sink.writeln()
if DEBUG_MODE:
self.post_return_code.writeln("/* end post-return code */")
self.post_return_code.flush_to(sink)
sink.writeln()
for cleanup_action in self.cleanup_actions:
sink.writeln(cleanup_action)
if self.return_type.get_c_type() != 'void':
sink.writeln()
sink.writeln("return retval;")
sink.unindent()
sink.writeln("}")
class TypeHandler(object):
def __init__(self, wrapper, **props):
assert isinstance(wrapper, ReverseWrapper)
self.wrapper = wrapper
self.props = props
class ReturnType(TypeHandler):
def get_c_type(self):
raise NotImplementedError
def write_decl(self):
raise NotImplementedError
def write_error_return(self):
'''Write "return <value>" code in case of error'''
raise NotImplementedError
def write_conversion(self):
'''Writes code to convert Python return value in 'py_retval'
into C 'retval'. Returns a string with C boolean expression
that determines if anything went wrong. '''
raise NotImplementedError
class Parameter(TypeHandler):
def __init__(self, wrapper, name, **props):
TypeHandler.__init__(self, wrapper, **props)
self.name = name
def get_c_type(self):
raise NotImplementedError
def convert_c2py(self):
'''Write some code before calling the Python method.'''
pass
def format_for_c_proto(self):
return join_ctype_name(self.get_c_type(), self.name)
###---
class StringParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'char *').replace('const-', 'const ')
def convert_c2py(self):
if self.props.get('optional', False):
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
self.wrapper.write_code(code=("if (%s)\n"
" py_%s = PyString_FromString(%s);\n"
% (self.name, self.name, self.name)),
cleanup=("Py_XDECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
else:
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
failure_expression=("!py_%s" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
'gchar-const*', 'string', 'static_string'):
argtypes.matcher.register_reverse(ctype, StringParam)
del ctype
class StringReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'char *').replace('const-', 'const ')
#return "char *"
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
#self.wrapper.add_declaration("char *retval;")
def write_error_return(self):
self.wrapper.write_code("return NULL;")
def write_conversion(self):
self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
for ctype in ('char*', 'gchar*', 'const-gchar*'):
argtypes.matcher.register_reverse_ret(ctype, StringReturn)
del ctype
class VoidReturn(ReturnType):
def get_c_type(self):
return "void"
def write_decl(self):
pass
def write_error_return(self):
self.wrapper.write_code("return;")
def write_conversion(self):
self.wrapper.add_pyret_parse_item("", "", prepend=True)
argtypes.matcher.register_reverse_ret('void', VoidReturn)
argtypes.matcher.register_reverse_ret('none', VoidReturn)
class GObjectParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'GObject *')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
self.wrapper.write_code(code=("if (%s)\n"
" py_%s = pygobject_new((GObject *) %s);\n"
"else {\n"
" Py_INCREF(Py_None);\n"
" py_%s = Py_None;\n"
"}"
% (self.name, self.name, self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse('GObject*', GObjectParam)
class GObjectReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'GObject *')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return NULL;")
def write_conversion(self):
self.wrapper.write_code(
code=None,
failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
% self.get_c_type())
self.wrapper.write_code("g_object_ref((GObject *) retval);")
argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
class IntParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'int')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
class IntReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'int')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return -G_MAXINT;")
def write_conversion(self):
self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
'gint16', 'gint32', 'GTime'):
argtypes.matcher.register_reverse(argtype, IntParam)
argtypes.matcher.register_reverse_ret(argtype, IntReturn)
del argtype
class IntPtrParam(Parameter):
def __init__(self, wrapper, name, **props):
if "direction" not in props:
raise argtypes.ArgTypeConfigurationError(
"cannot use int* parameter without direction")
if props["direction"] not in ("out", "inout"):
raise argtypes.ArgTypeConfigurationError(
"cannot use int* parameter with direction '%s'"
% (props["direction"],))
Parameter.__init__(self, wrapper, name, **props)
def get_c_type(self):
return self.props.get('c_type', 'int*')
def convert_c2py(self):
if self.props["direction"] == "inout":
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
self.wrapper.add_pyret_parse_item("i", self.name)
for argtype in ('int*', 'gint*'):
argtypes.matcher.register_reverse(argtype, IntPtrParam)
del argtype
class GEnumReturn(IntReturn):
def write_conversion(self):
self.wrapper.write_code(
code=None,
failure_expression=(
"pyg_enum_get_value(%s, py_retval, (gint *)&retval)"
% (self.props['typecode'],)))
argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
class GEnumParam(IntParam):
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
(self.name, self.props['typecode'], self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
failure_expression=("!py_%s" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GEnum", GEnumParam)
class GFlagsReturn(IntReturn):
def write_conversion(self):
self.wrapper.write_code(
code=None,
failure_expression=(
"pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
self.props['typecode']))
argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
class GFlagsParam(IntParam):
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=(
"py_%s = pyg_flags_from_gtype(%s, %s);" %
(self.name, self.props['typecode'], self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
failure_expression=("!py_%s" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GFlags", GFlagsParam)
class GtkTreePathParam(IntParam):
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=(
"py_%s = pygtk_tree_path_to_pyobject(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
failure_expression=("!py_%s" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
class GtkTreePathReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'GtkTreePath *')
def write_decl(self):
self.wrapper.add_declaration("GtkTreePath * retval;")
def write_error_return(self):
self.wrapper.write_code("return NULL;")
def write_conversion(self):
self.wrapper.write_code(
"retval = pygtk_tree_path_from_pyobject(py_retval);\n",
failure_expression=('!retval'),
failure_exception=(
'PyErr_SetString(PyExc_TypeError, "retval should be a GtkTreePath");'))
argtypes.matcher.register_reverse_ret("GtkTreePath*", GtkTreePathReturn)
class BooleanReturn(ReturnType):
def get_c_type(self):
return "gboolean"
def write_decl(self):
self.wrapper.add_declaration("gboolean retval;")
self.wrapper.add_declaration("PyObject *py_main_retval;")
def write_error_return(self):
self.wrapper.write_code("return FALSE;")
def write_conversion(self):
self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
self.wrapper.write_code(
"retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
code_sink=self.wrapper.post_return_code)
argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
class BooleanParam(Parameter):
def get_c_type(self):
return "gboolean"
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
% (self.name, self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("gboolean", BooleanParam)
class DoubleParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'gdouble')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
class DoublePtrParam(Parameter):
def __init__(self, wrapper, name, **props):
if "direction" not in props:
raise argtypes.ArgTypeConfigurationError(
"cannot use double* parameter without direction")
if props["direction"] not in ("out", ): # inout not yet implemented
raise argtypes.ArgTypeConfigurationError(
"cannot use double* parameter with direction '%s'"
% (props["direction"],))
Parameter.__init__(self, wrapper, name, **props)
def get_c_type(self):
return self.props.get('c_type', 'double*')
def convert_c2py(self):
self.wrapper.add_pyret_parse_item("d", self.name)
for argtype in ('double*', 'gdouble*'):
argtypes.matcher.register_reverse(argtype, DoublePtrParam)
del argtype
class DoubleReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'gdouble')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return -G_MAXFLOAT;")
def write_conversion(self):
self.wrapper.add_pyret_parse_item("d", "&retval", prepend=True)
for argtype in ('float', 'double', 'gfloat', 'gdouble'):
argtypes.matcher.register_reverse(argtype, DoubleParam)
argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
class GBoxedParam(Parameter):
def get_c_type(self):
return self.props.get('c_type').replace('const-', 'const ')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
ctype = self.get_c_type()
if ctype.startswith('const '):
ctype_no_const = ctype[len('const '):]
self.wrapper.write_code(
code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
(self.name, self.props['typecode'],
ctype_no_const, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
else:
self.wrapper.write_code(
code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
(self.name, self.props['typecode'], self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
class GBoxedReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return retval;")
def write_conversion(self):
self.wrapper.write_code(code = None,
failure_expression=("!pyg_boxed_check(py_retval, %s)" %
(self.props['typecode'],)),
failure_exception=(
'PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
% (self.props['typename'],)))
self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
self.props['typename'])
argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
class GdkRegionPtrReturn(GBoxedReturn):
def write_error_return(self):
self.wrapper.write_code("return gdk_region_new();")
def write_conversion(self):
self.props['typecode'] = 'PYGDK_TYPE_REGION'
self.props['typename'] = 'GdkRegion'
super(GdkRegionPtrReturn, self).write_conversion()
argtypes.matcher.register_reverse_ret("GdkRegion*", GdkRegionPtrReturn)
class PangoFontDescriptionReturn(GBoxedReturn):
def write_error_return(self):
self.wrapper.write_code("return pango_font_description_new();")
def write_conversion(self):
self.props['typecode'] = 'PANGO_TYPE_FONT_DESCRIPTION'
self.props['typename'] = 'PangoFontDescription'
super(PangoFontDescriptionReturn, self).write_conversion()
argtypes.matcher.register_reverse_ret("PangoFontDescription*",
PangoFontDescriptionReturn)
class PangoFontMetricsReturn(GBoxedReturn):
def write_error_return(self):
self.wrapper.write_code("return pango_font_metrics_new();")
def write_conversion(self):
self.props['typecode'] = 'PANGO_TYPE_FONT_METRICS'
self.props['typename'] = 'PangoFontMetrics'
super(PangoFontMetricsReturn, self).write_conversion()
argtypes.matcher.register_reverse_ret("PangoFontMetrics*",
PangoFontMetricsReturn)
class PangoLanguageReturn(GBoxedReturn):
def write_error_return(self):
self.wrapper.write_code("return pango_language_from_string(\"\");")
def write_conversion(self):
self.props['typecode'] = 'PANGO_TYPE_LANGUAGE'
self.props['typename'] = 'PangoLanguage'
super(PangoLanguageReturn, self).write_conversion()
argtypes.matcher.register_reverse_ret("PangoLanguage*", PangoLanguageReturn)
class GdkRectanglePtrParam(Parameter):
def get_c_type(self):
return self.props.get('c_type').replace('const-', 'const ')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(
code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
class GErrorParam(Parameter):
def get_c_type(self):
return self.props.get('c_type').replace('**', ' **')
def convert_c2py(self):
self.wrapper.write_code(code=None,
failure_expression=("pyg_gerror_exception_check(%s)" % self.name),
code_sink=self.wrapper.check_exception_code)
argtypes.matcher.register_reverse('GError**', GErrorParam)
class PyGObjectMethodParam(Parameter):
def __init__(self, wrapper, name, method_name, **props):
Parameter.__init__(self, wrapper, name, **props)
self.method_name = method_name
def get_c_type(self):
return self.props.get('c_type', 'GObject *')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
failure_expression=("!py_%s" % self.name))
self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
class CallbackInUserDataParam(Parameter):
def __init__(self, wrapper, name, free_it, **props):
Parameter.__init__(self, wrapper, name, **props)
self.free_it = free_it
def get_c_type(self):
return "gpointer"
def convert_c2py(self):
self.wrapper.add_declaration("PyObject **_user_data;")
cleanup = self.free_it and ("g_free(%s);" % self.name) or None
self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
% self.name),
cleanup=cleanup)
self.wrapper.add_declaration("PyObject *py_func;")
cleanup = self.free_it and "Py_DECREF(py_func);" or None
self.wrapper.write_code(code="py_func = _user_data[0];",
cleanup=cleanup)
self.wrapper.set_call_target("py_func")
self.wrapper.add_declaration("PyObject *py_user_data;")
cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
self.wrapper.write_code(code="py_user_data = _user_data[1];",
cleanup=cleanup)
self.wrapper.add_pyargv_item("py_user_data", optional=True)
def _test():
import sys
if 1:
wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
wrapper.set_return_type(StringReturn(wrapper))
wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
wrapper.add_parameter(GObjectParam(wrapper, "param3"))
#wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
wrapper.generate(FileCodeSink(sys.stderr))
if 0:
wrapper = ReverseWrapper("this_a_callback_wrapper")
wrapper.set_return_type(VoidReturn(wrapper))
wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
wrapper.add_parameter(GObjectParam(wrapper, "param2"))
wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
wrapper.generate(FileCodeSink(sys.stderr))
if __name__ == '__main__':
_test()

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
from __future__ import generators
import string
from cStringIO import StringIO
class error(Exception):
def __init__(self, filename, lineno, msg):
Exception.__init__(self, msg)
self.filename = filename
self.lineno = lineno
self.msg = msg
def __str__(self):
return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg)
trans = [' '] * 256
for i in range(256):
if chr(i) in string.letters + string.digits + '_':
trans[i] = chr(i)
else:
trans[i] = '_'
trans = string.join(trans, '')
def parse(filename):
if isinstance(filename, str):
fp = open(filename, 'r')
else: # if not string, assume it is some kind of iterator
fp = filename
filename = getattr(fp, 'name', '<unknown>')
whitespace = ' \t\n\r\x0b\x0c'
nonsymbol = whitespace + '();\'"'
stack = []
openlines = []
lineno = 0
for line in fp:
pos = 0
lineno += 1
while pos < len(line):
if line[pos] in whitespace: # ignore whitespace
pass
elif line[pos] == ';': # comment
break
elif line[pos:pos+2] == "'(":
pass # the open parenthesis will be handled next iteration
elif line[pos] == '(':
stack.append(())
openlines.append(lineno)
elif line[pos] == ')':
if len(stack) == 0:
raise error(filename, lineno, 'close parenthesis found when none open')
closed = stack[-1]
del stack[-1]
del openlines[-1]
if stack:
stack[-1] += (closed,)
else:
yield closed
elif line[pos] == '"': # quoted string
if not stack:
raise error(filename, lineno,
'string found outside of s-expression')
endpos = pos + 1
chars = []
while endpos < len(line):
if endpos+1 < len(line) and line[endpos] == '\\':
endpos += 1
if line[endpos] == 'n':
chars.append('\n')
elif line[endpos] == 'r':
chars.append('\r')
elif line[endpos] == 't':
chars.append('\t')
else:
chars.append('\\')
chars.append(line[endpos])
elif line[endpos] == '"':
break
else:
chars.append(line[endpos])
endpos += 1
if endpos >= len(line):
raise error(filename, lineno, "unclosed quoted string")
pos = endpos
stack[-1] += (''.join(chars),)
else: # symbol/number
if not stack:
raise error(filename, lineno,
'identifier found outside of s-expression')
endpos = pos
while endpos < len(line) and line[endpos] not in nonsymbol:
endpos += 1
symbol = line[pos:endpos]
pos = max(pos, endpos-1)
try: symbol = int(symbol)
except ValueError:
try: symbol = float(symbol)
except ValueError: pass
stack[-1] += (symbol,)
pos += 1
if len(stack) != 0:
msg = '%d unclosed parentheses found at end of ' \
'file (opened on line(s) %s)' % (len(stack),
', '.join(map(str, openlines)))
raise error(filename, lineno, msg)
class Parser:
def __init__(self, filename):
"""Argument is either a string, a parse tree, or file object"""
self.filename = filename
def startParsing(self, filename=None):
statements = parse(filename or self.filename)
for statement in statements:
self.handle(statement)
def handle(self, tup):
cmd = string.translate(tup[0], trans)
if hasattr(self, cmd):
getattr(self, cmd)(*tup[1:])
else:
self.unknown(tup)
def unknown(self, tup):
pass
_testString = """; a scheme file
(define-func gdk_font_load ; a comment at end of line
GdkFont
((string name)))
(define-boxed GdkEvent
gdk_event_copy
gdk_event_free
"sizeof(GdkEvent)")
"""
if __name__ == '__main__':
import sys
if sys.argv[1:]:
fp = open(sys.argv[1])
else:
fp = StringIO(_testString)
statements = parse(fp)
for s in statements:
print `s`

View File

@ -0,0 +1,544 @@
/*
* moopython-api.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOO_PYTHON_API_H
#define MOO_PYTHON_API_H
#include "moopython/moopython-utils.h"
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
#include <glib/gprintf.h>
// static MooPyObject *
// moo_python_api_run_simple_string (const char *str)
// {
// PyObject *dict, *main_mod;
// g_return_val_if_fail (str != NULL, NULL);
// main_mod = PyImport_AddModule ("__main__");
// dict = PyModule_GetDict (main_mod);
// return (MooPyObject*) PyRun_String (str, Py_file_input, dict, dict);
// }
//
//
// static MooPyObject *
// moo_python_api_create_script_dict (const char *name)
// {
// PyObject *dict, *builtins;
//
// builtins = PyImport_ImportModule ("__builtin__");
// g_return_val_if_fail (builtins != NULL, NULL);
//
// dict = PyDict_New ();
// PyDict_SetItemString (dict, "__builtins__", builtins);
//
// if (name)
// {
// PyObject *py_name = PyString_FromString (name);
// PyDict_SetItemString (dict, "__name__", py_name);
// Py_XDECREF (py_name);
// }
//
// Py_XDECREF (builtins);
// return (MooPyObject*) dict;
// }
//
//
// static MooPyObject*
// moo_python_api_run_string (const char *str,
// MooPyObject *globals,
// MooPyObject *locals)
// {
// PyObject *ret;
//
// g_return_val_if_fail (str != NULL, NULL);
//
// if (!locals)
// locals = moo_python_api_create_script_dict ("__script__");
// else
// Py_INCREF ((PyObject*) locals);
//
// g_return_val_if_fail (locals != NULL, NULL);
//
// if (!globals)
// globals = locals;
//
// ret = PyRun_String (str, Py_file_input, (PyObject*) globals, (PyObject*) locals);
//
// Py_DECREF ((PyObject*) locals);
// return (MooPyObject*) ret;
// }
//
//
// static MooPyObject *
// moo_python_api_run_file (gpointer fp,
// const char *filename,
// MooPyObject *globals,
// MooPyObject *locals)
// {
// PyObject *ret;
//
// g_return_val_if_fail (fp != NULL && filename != NULL, NULL);
//
// if (!locals)
// locals = moo_python_api_create_script_dict ("__script__");
// else
// Py_INCREF ((PyObject*) locals);
//
// g_return_val_if_fail (locals != NULL, NULL);
//
// if (!globals)
// globals = locals;
//
// ret = PyRun_File (fp, filename, Py_file_input, (PyObject*) globals, (PyObject*) locals);
//
// Py_DECREF ((PyObject*) locals);
// return (MooPyObject*) ret;
// }
//
//
// static MooPyObject *
// moo_python_api_run_code (const char *str,
// MooPyObject *globals,
// MooPyObject *locals)
// {
// PyObject *ret;
//
// g_return_val_if_fail (str != NULL, NULL);
//
// if (!locals)
// locals = moo_python_api_create_script_dict ("__script__");
// else
// Py_INCREF ((PyObject*) locals);
//
// g_return_val_if_fail (locals != NULL, NULL);
//
// if (!globals)
// globals = locals;
//
// ret = PyRun_String (str, Py_file_input, (PyObject*) globals, (PyObject*) locals);
//
// if (ret)
// {
// Py_DECREF (ret);
//
// if (PyMapping_HasKeyString ((PyObject*) locals, "__retval__"))
// ret = PyMapping_GetItemString ((PyObject*) locals, "__retval__");
// else
// ret = NULL;
// }
//
// Py_DECREF ((PyObject*) locals);
// return (MooPyObject*) ret;
// }
//
//
// static MooPyObject*
// moo_python_api_incref (MooPyObject *obj)
// {
// Py_XINCREF ((PyObject*) obj);
// return obj;
// }
//
// static void
// moo_python_api_decref (MooPyObject *obj)
// {
// Py_XDECREF ((PyObject*) obj);
// }
//
//
// static MooPyObject *
// moo_python_api_py_object_from_gobject (gpointer gobj)
// {
// g_return_val_if_fail (!gobj || G_IS_OBJECT (gobj), NULL);
// return (MooPyObject*) pygobject_new (gobj);
// }
//
// static gpointer
// moo_python_api_gobject_from_py_object (MooPyObject *pyobj)
// {
// GValue val;
//
// g_return_val_if_fail (pyobj != NULL, NULL);
//
// val.g_type = 0;
// g_value_init (&val, G_TYPE_OBJECT);
//
// if (pyg_value_from_pyobject (&val, (PyObject*) pyobj) == 0)
// {
// gpointer ret = g_value_get_object (&val);
// g_value_unset (&val);
// return ret;
// }
//
// PyErr_Clear ();
// return NULL;
// }
//
//
// static MooPyObject *
// moo_python_api_dict_get_item (MooPyObject *dict,
// const char *key)
// {
// g_return_val_if_fail (dict != NULL, NULL);
// g_return_val_if_fail (key != NULL, NULL);
// return (MooPyObject*) PyDict_GetItemString ((PyObject*) dict, (char*) key);
// }
//
// static gboolean
// moo_python_api_dict_set_item (MooPyObject *dict,
// const char *key,
// MooPyObject *val)
// {
// g_return_val_if_fail (dict != NULL, FALSE);
// g_return_val_if_fail (key != NULL, FALSE);
// g_return_val_if_fail (val != NULL, FALSE);
//
// if (PyDict_SetItemString ((PyObject*) dict, (char*) key, (PyObject*) val))
// {
// PyErr_Print ();
// return FALSE;
// }
//
// return TRUE;
// }
//
// static gboolean
// moo_python_api_dict_del_item (MooPyObject *dict,
// const char *key)
// {
// g_return_val_if_fail (dict != NULL, FALSE);
// g_return_val_if_fail (key != NULL, FALSE);
//
// if (PyDict_DelItemString ((PyObject*) dict, (char*) key))
// {
// PyErr_Print ();
// return FALSE;
// }
//
// return TRUE;
// }
//
//
// static void G_GNUC_PRINTF(2,3)
// moo_python_api_set_error (int type,
// const char *format,
// ...)
// {
// PyObject *exception = NULL;
// char *msg = NULL;
// va_list args;
//
// va_start (args, format);
// g_vasprintf (&msg, format, args);
// va_end (args);
//
// g_return_if_fail (msg != NULL);
//
// switch (type)
// {
// case MOO_PY_RUNTIME_ERROR:
// exception = PyExc_RuntimeError;
// break;
// case MOO_PY_TYPE_ERROR:
// exception = PyExc_TypeError;
// break;
// case MOO_PY_VALUE_ERROR:
// exception = PyExc_ValueError;
// break;
// case MOO_PY_NOT_IMPLEMENTED_ERROR:
// exception = PyExc_NotImplementedError;
// break;
// }
//
// g_return_if_fail (exception != NULL);
//
// PyErr_SetString (exception, (char*) msg);
// }
//
//
// static void
// moo_python_api_py_err_print (void)
// {
// PyErr_Print ();
// }
//
//
// static char *
// moo_python_api_get_info (void)
// {
// return g_strdup_printf ("%s %s", Py_GetVersion (), Py_GetPlatform ());
// }
//
//
// static MooPyObject *
// moo_python_api_import_exec (const char *name,
// const char *string)
// {
// PyObject *code;
// PyObject *mod;
// char *filename;
//
// g_return_val_if_fail (name != NULL, NULL);
// g_return_val_if_fail (string != NULL, NULL);
//
// filename = g_strdup_printf ("%s.py", name);
// code = Py_CompileString (string, filename, Py_file_input);
// g_free (filename);
//
// if (!code)
// return FALSE;
//
// mod = PyImport_ExecCodeModule ((char*) name, code);
//
// Py_DECREF (code);
// return (MooPyObject*) mod;
// }
//
//
// static MooPyObject *
// call_function_valist (MooPyObject *callable,
// const char *format,
// va_list vargs)
// {
// PyObject *args = NULL, *ret = NULL;
//
// if (format && *format)
// args = Py_VaBuildValue ((char*) format, vargs);
// else
// args = PyTuple_New (0);
//
// if (!args)
// goto out;
//
// if (!PyTuple_Check (args))
// {
// PyObject *tmp = PyTuple_New (1);
//
// if (!tmp)
// goto out;
//
// if (PyTuple_SetItem (tmp, 0, args) < 0)
// {
// Py_XDECREF (tmp);
// goto out;
// }
//
// args = tmp;
// }
//
// ret = PyObject_Call ((PyObject*) callable, args, NULL);
//
// out:
// Py_XDECREF (args);
// return (MooPyObject*) ret;
// }
//
// static MooPyObject *
// moo_python_api_py_object_call_method (MooPyObject *object,
// const char *method,
// const char *format,
// ...)
// {
// va_list vargs;
// MooPyObject *ret;
// PyObject *callable;
//
// callable = PyObject_GetAttrString ((PyObject*) object, (char*) method);
//
// if (!callable)
// return NULL;
//
// va_start (vargs, format);
// ret = call_function_valist ((MooPyObject*) callable, format, vargs);
// va_end (vargs);
//
// Py_XDECREF (callable);
// return (MooPyObject*) ret;
// }
//
// static MooPyObject *
// moo_python_api_py_object_call_function (MooPyObject *callable,
// const char *format,
// ...)
// {
// va_list vargs;
// MooPyObject *ret;
//
// va_start (vargs, format);
// ret = call_function_valist (callable, format, vargs);
// va_end (vargs);
//
// return (MooPyObject*) ret;
// }
//
//
// static int
// convert_meth_flags (int moo_flags)
// {
// int flags = 0;
//
// if (moo_flags & MOO_PY_METH_VARARGS)
// flags |= METH_VARARGS;
// if (moo_flags & MOO_PY_METH_KEYWORDS)
// flags |= METH_KEYWORDS;
// if (moo_flags & MOO_PY_METH_NOARGS)
// flags |= METH_NOARGS;
// if (moo_flags & MOO_PY_METH_O)
// flags |= METH_O;
// if (moo_flags & MOO_PY_METH_CLASS)
// flags |= METH_CLASS;
// if (moo_flags & MOO_PY_METH_STATIC)
// flags |= METH_STATIC;
//
// return flags;
// }
//
// static MooPyObject *
// moo_python_api_py_c_function_new (MooPyMethodDef *meth,
// MooPyObject *self)
// {
// PyMethodDef *py_meth;
//
// g_return_val_if_fail (meth != NULL, NULL);
// g_return_val_if_fail (meth->ml_meth != NULL, NULL);
// g_return_val_if_fail (meth->ml_name != NULL, NULL);
//
// py_meth = g_new0 (PyMethodDef, 1);
// moo_python_add_data (py_meth, g_free);
//
// py_meth->ml_name = (char*) meth->ml_name;
// py_meth->ml_meth = (PyCFunction) meth->ml_meth;
// py_meth->ml_flags = convert_meth_flags (meth->ml_flags);
// py_meth->ml_doc = (char*) meth->ml_doc;
//
// return (MooPyObject*) PyCFunction_New (py_meth, (PyObject*) self);
// }
//
//
// static int
// moo_python_api_py_module_add_object (MooPyObject *mod,
// const char *name,
// MooPyObject *obj)
// {
// return PyModule_AddObject ((PyObject*) mod, (char*) name, (PyObject*) obj);
// }
//
//
// static gboolean
// moo_python_api_py_arg_parse_tuple (MooPyObject *args,
// const char *format,
// ...)
// {
// int ret;
// va_list vargs;
//
// va_start (vargs, format);
// ret = PyArg_VaParse ((PyObject*) args, (char*) format, vargs);
// va_end (vargs);
//
// return ret;
// }
static gboolean
moo_python_api_init (void)
{
static int argc;
static char **argv;
// static MooPyAPI api = {
// NULL, NULL, NULL,
// moo_python_api_incref,
// moo_python_api_decref,
// moo_python_api_get_info,
// moo_python_api_run_simple_string,
// moo_python_api_run_string,
// moo_python_api_run_file,
// moo_python_api_run_code,
// moo_python_api_create_script_dict,
// moo_python_api_py_object_from_gobject,
// moo_python_api_gobject_from_py_object,
// moo_python_api_dict_get_item,
// moo_python_api_dict_set_item,
// moo_python_api_dict_del_item,
// moo_python_api_import_exec,
//
// moo_python_api_set_error,
// moo_python_api_py_err_print,
// moo_python_api_py_object_call_method,
// moo_python_api_py_object_call_function,
// moo_python_api_py_c_function_new,
// moo_python_api_py_module_add_object,
// moo_python_api_py_arg_parse_tuple,
// NULL
// };
//
// g_return_val_if_fail (!moo_python_running(), FALSE);
//
// if (!moo_python_init (MOO_PY_API_VERSION, &api))
// {
// g_warning ("%s: oops", G_STRLOC);
// return FALSE;
// }
//
// g_assert (moo_python_running ());
if (!Py_IsInitialized ())
{
if (!argv)
{
argc = 1;
argv = g_new0 (char*, 2);
argv[0] = g_strdup ("");
}
#if PY_MINOR_VERSION >= 4
/* do not let python install signal handlers */
Py_InitializeEx (FALSE);
#else
Py_Initialize ();
#endif
/* pygtk wants sys.argv */
PySys_SetArgv (argc, argv);
_moo_py_init_print_funcs ();
}
// api.py_none = (gpointer) Py_None;
//
// #ifndef MOO_DEBUG_ENABLED
// api.py_true = (MooPyObject*) Py_True;
// api.py_false = (MooPyObject*) Py_False;
// #else
// /* avoid strict aliasing warnings */
// api.py_true = (gpointer) &(_Py_TrueStruct);
// api.py_false = (gpointer) &(_Py_ZeroStruct);
// #endif
return TRUE;
}
inline static void
moo_python_api_deinit (void)
{
// moo_python_init (MOO_PY_API_VERSION, NULL);
}
#endif /* MOO_PYTHON_API_H */

View File

@ -0,0 +1,64 @@
/*
* moopython.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#define NO_IMPORT_PYGTK
#include <pygobject.h>
#include <pygtk/pygtk.h>
#include "mooedit/mooplugin-loader.h"
#include "moopython/moopython-builtin.h"
#include "moopython/moopython-api.h"
#include "moopython/moopython-loader.h"
#include "moopython/pygtk/moo-pygtk.h"
#include "moopython/moopython-pygtkmod.h"
#include "mooutils/mooutils-misc.h"
gboolean
_moo_python_builtin_init (void)
{
if (!Py_IsInitialized ())
{
if (!moo_python_api_init ())
{
g_warning ("%s: oops", G_STRLOC);
return FALSE;
}
if (!_moo_pygtk_init ())
{
g_warning ("%s: could not initialize moo module", G_STRLOC);
PyErr_Print ();
moo_python_api_deinit ();
return FALSE;
}
#ifndef MOO_BUILD_MOO_MODULE
reset_log_func ();
#endif
}
if (!moo_plugin_loader_lookup (MOO_PYTHON_PLUGIN_LOADER_ID))
{
MooPluginLoader *loader = _moo_python_get_plugin_loader ();
moo_plugin_loader_register (loader, MOO_PYTHON_PLUGIN_LOADER_ID);
_moo_python_plugin_loader_free (loader);
}
return TRUE;
}

View File

@ -0,0 +1,29 @@
/*
* moopython-builtin.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOO_PYTHON_BUILTIN_H
#define MOO_PYTHON_BUILTIN_H
#include <glib.h>
G_BEGIN_DECLS
gboolean _moo_python_builtin_init (void);
G_END_DECLS
#endif /* MOO_PYTHON_BUILTIN_H */

View File

@ -0,0 +1,271 @@
/*
* moopython-loader.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
#include <string.h>
#include "moopython/moopython-loader.h"
#include "mooutils/mooutils-misc.h"
#define LIBDIR "lib"
static gboolean
sys_path_add_dir (const char *dir)
{
PyObject *path;
PyObject *s;
path = PySys_GetObject ((char*) "path");
if (!path)
{
PyErr_Print ();
return FALSE;
}
if (!PyList_Check (path))
{
g_critical ("sys.path is not a list");
return FALSE;
}
s = PyString_FromString (dir);
PyList_Append (path, s);
Py_DECREF (s);
return TRUE;
}
static void
sys_path_remove_dir (const char *dir)
{
PyObject *path;
int i;
path = PySys_GetObject ((char*) "path");
if (!path || !PyList_Check (path))
return;
for (i = PyList_GET_SIZE (path) - 1; i >= 0; --i)
{
PyObject *item = PyList_GET_ITEM (path, i);
if (PyString_CheckExact (item) &&
!strcmp (PyString_AsString (item), dir))
{
if (PySequence_DelItem (path, i) != 0)
PyErr_Print ();
break;
}
}
}
static void
sys_path_add_plugin_dirs (void)
{
char **d;
char **dirs;
static gboolean been_here = FALSE;
if (been_here)
return;
been_here = TRUE;
dirs = moo_plugin_get_dirs ();
for (d = dirs; d && *d; ++d)
{
char *libdir = g_build_filename (*d, LIBDIR, NULL);
sys_path_add_dir (libdir);
g_free (libdir);
}
g_strfreev (dirs);
}
static PyObject *
do_load_file (const char *path)
{
PyObject *mod = NULL;
PyObject *code;
char *modname = NULL, *content = NULL;
GError *error = NULL;
if (!g_file_get_contents (path, &content, NULL, &error))
{
g_warning ("could not read file '%s': %s", path, error->message);
g_error_free (error);
return NULL;
}
modname = g_strdup_printf ("moo_module_%08x", g_random_int ());
code = Py_CompileString (content, path, Py_file_input);
if (!code)
{
PyErr_Print ();
goto out;
}
moo_disable_win32_error_message ();
mod = PyImport_ExecCodeModule (modname, code);
moo_enable_win32_error_message ();
Py_DECREF (code);
if (!mod)
{
if (PyErr_ExceptionMatches (PyExc_Exception))
{
PyObject *type, *value, *traceback;
PyObject *r;
char *s;
PyErr_Fetch (&type, &value, &traceback);
PyErr_NormalizeException (&type, &value, &traceback);
r = PyObject_Repr (value);
s = r ? PyString_AsString (r) : NULL;
if (s && strcmp (s, "PluginWontLoad") == 0)
{
Py_XDECREF (r);
Py_XDECREF (type);
Py_XDECREF (value);
Py_XDECREF (traceback);
goto out;
}
Py_XDECREF (r);
PyErr_Restore(type, value, traceback);
}
g_warning ("error when loading file '%s'", path);
PyErr_Print ();
goto out;
}
out:
g_free (content);
g_free (modname);
return mod;
}
static PyObject *
load_file (const char *path)
{
char *dirname;
gboolean dir_added;
PyObject *retval;
g_return_val_if_fail (path != NULL, NULL);
sys_path_add_plugin_dirs ();
dirname = g_path_get_dirname (path);
dir_added = sys_path_add_dir (dirname);
retval = do_load_file (path);
if (dir_added)
sys_path_remove_dir (dirname);
g_free (dirname);
return retval;
}
static void
load_python_module (const char *module_file,
G_GNUC_UNUSED const char *ini_file,
G_GNUC_UNUSED gpointer data)
{
PyObject *mod;
mod = load_file (module_file);
Py_XDECREF (mod);
}
static void
load_python_plugin (const char *plugin_file,
const char *plugin_id,
MooPluginInfo *info,
MooPluginParams *params,
G_GNUC_UNUSED const char *ini_file,
G_GNUC_UNUSED gpointer data)
{
PyObject *mod;
PyObject *py_plugin_type;
GType plugin_type;
if (!(mod = load_file (plugin_file)))
return;
py_plugin_type = PyObject_GetAttrString (mod, "__plugin__");
if (!py_plugin_type)
{
g_warning ("file %s doesn't define __plugin__ attribute",
plugin_file);
}
else if (py_plugin_type == Py_None)
{
/* it's fine, ignore */
}
else if (!PyType_Check (py_plugin_type))
{
g_warning ("__plugin__ attribute in file %s is not a type",
plugin_file);
}
else if (!(plugin_type = pyg_type_from_object (py_plugin_type)))
{
g_warning ("__plugin__ attribute in file %s is not a valid type",
plugin_file);
PyErr_Clear ();
}
else if (!g_type_is_a (plugin_type, MOO_TYPE_PLUGIN))
{
g_warning ("__plugin__ attribute in file %s is not a MooPlugin subclass",
plugin_file);
}
else
{
moo_plugin_register (plugin_id, plugin_type, info, params);
}
Py_XDECREF (py_plugin_type);
Py_XDECREF (mod);
}
MooPluginLoader *
_moo_python_get_plugin_loader (void)
{
MooPluginLoader *loader = g_new0 (MooPluginLoader, 1);
loader->load_module = load_python_module;
loader->load_plugin = load_python_plugin;
return loader;
}

View File

@ -0,0 +1,32 @@
/*
* moopython-loader.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOO_PYTHON_LOADER_H
#define MOO_PYTHON_LOADER_H
#include <mooedit/mooplugin-loader.h>
G_BEGIN_DECLS
#define MOO_PYTHON_PLUGIN_LOADER_ID "Python"
MooPluginLoader *_moo_python_get_plugin_loader (void);
#define _moo_python_plugin_loader_free g_free
G_END_DECLS
#endif /* MOO_PYTHON_LOADER_H */

View File

@ -0,0 +1,107 @@
/*
* moopython-pygtkmod.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mooutils/mooutils-misc.h"
G_GNUC_UNUSED static void
init_pygtk_mod (void)
{
PyObject *gobject, *pygtk;
PyObject *mdict;
PyObject *cobject;
if (!(gobject = PyImport_ImportModule ("gobject")))
return;
mdict = PyModule_GetDict (gobject);
cobject = PyDict_GetItemString (mdict, "_PyGObject_API");
if (!cobject || !PyCObject_Check (cobject))
{
PyErr_SetString (PyExc_RuntimeError,
"could not find _PyGObject_API object");
return;
}
_PyGObject_API = (struct _PyGObject_Functions *) PyCObject_AsVoidPtr (cobject);
if (!(pygtk = PyImport_ImportModule("gtk._gtk")))
return;
mdict = PyModule_GetDict (pygtk);
cobject = PyDict_GetItemString (mdict, "_PyGtk_API");
if (!cobject || !PyCObject_Check (cobject))
{
PyErr_SetString (PyExc_RuntimeError,
"could not find _PyGtk_API object");
return;
}
_PyGtk_API = (struct _PyGtk_FunctionStruct*) PyCObject_AsVoidPtr (cobject);
}
inline static gboolean
check_pygtk_version (const char *module,
int req_major,
int req_minor,
int req_micro)
{
PyObject *mod, *mdict, *version;
int found_major, found_minor, found_micro;
mod = PyImport_ImportModule ((char*) module);
g_return_val_if_fail (mod != NULL, FALSE);
mdict = PyModule_GetDict (mod);
version = PyDict_GetItemString (mdict, "pygobject_version");
if (!version)
version = PyDict_GetItemString (mdict, "pygtk_version");
if (!version)
return FALSE;
if (!PyArg_ParseTuple (version, "iii", &found_major, &found_minor, &found_micro))
{
PyErr_Print ();
return FALSE;
}
if (req_major != found_major ||
req_minor > found_minor ||
(req_minor == found_minor && req_micro > found_micro))
return FALSE;
return TRUE;
}
G_GNUC_UNUSED static void
reset_log_func (void)
{
#ifdef pyg_disable_warning_redirections
if (check_pygtk_version ("gobject", 2, 12, 0))
pyg_disable_warning_redirections ();
else
moo_reset_log_func ();
#else
moo_reset_log_func ();
#endif
}

View File

@ -0,0 +1,461 @@
/*
* moopython/moopython-utils.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Python.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "moopython/moopython-utils.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mootype-macros.h"
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
MOO_DEFINE_BOXED_TYPE_R (MooPyObject, _moo_py_object)
PyObject *
_moo_strv_to_pyobject (char **strv)
{
PyObject *result;
guint len, i;
if (!strv)
return_None;
len = g_strv_length (strv);
result = PyTuple_New (len);
for (i = 0; i < len; ++i)
{
PyTuple_SET_ITEM (result, i,
PyString_FromString (strv[i]));
}
return result;
}
static char **
_moo_pyobject_to_strv_no_check (PyObject *seq,
int len)
{
#define CACHE_SIZE 10
static char **cache[CACHE_SIZE];
static guint n;
int i;
char **ret;
g_strfreev (cache[n]);
cache[n] = ret = g_new (char*, len + 1);
ret[len] = NULL;
for (i = 0; i < len; ++i)
{
PyObject *item = PySequence_ITEM (seq, i);
ret[i] = g_strdup (PyString_AS_STRING (item));
}
if (++n == CACHE_SIZE)
n = 0;
return ret;
#undef CACHE_SIZE
}
int _moo_pyobject_to_strv (PyObject *obj, char ***dest)
{
int len, i;
if (obj == Py_None)
{
*dest = NULL;
return TRUE;
}
if (!PySequence_Check (obj))
{
PyErr_SetString (PyExc_TypeError,
"argument must be a sequence");
return FALSE;
}
len = PySequence_Size (obj);
if (len < 0)
{
PyErr_SetString (PyExc_RuntimeError,
"got negative length of a sequence");
return FALSE;
}
for (i = 0; i < len; ++i)
{
PyObject *item = PySequence_ITEM (obj, i);
g_return_val_if_fail (item != NULL, FALSE);
if (!PyString_Check (item))
{
PyErr_SetString (PyExc_TypeError,
"argument must be a sequence of strings");
return FALSE;
}
}
*dest = _moo_pyobject_to_strv_no_check (obj, len);
return TRUE;
}
int
_moo_pyobject_to_strv_no_null (PyObject *obj,
char ***dest)
{
if (obj == Py_None)
{
PyErr_SetString (PyExc_TypeError,
"argument must be a sequence, not None");
return FALSE;
}
return _moo_pyobject_to_strv (obj, dest);
}
PyObject *_moo_gvalue_to_pyobject (const GValue *val)
{
PyObject *obj;
obj = pyg_value_as_pyobject (val, TRUE);
if (!obj && !PyErr_Occurred ())
{
g_critical ("%s: oops", G_STRLOC);
PyErr_Format (PyExc_TypeError, "could not convert value of type %s",
g_type_name (G_VALUE_TYPE (val)));
}
return obj;
}
void
_moo_pyobject_to_gvalue (PyObject *object,
GValue *value)
{
GType type;
g_return_if_fail (value != NULL && !G_IS_VALUE (value));
g_return_if_fail (object != NULL);
type = pyg_type_from_object (object);
if (type != 0 && type != G_TYPE_NONE)
{
g_value_init (value, type);
if (pyg_value_from_pyobject (value, object) == 0)
return;
g_critical ("%s: oops", G_STRLOC);
g_value_unset (value);
}
PyErr_Clear ();
g_value_init (value, MOO_TYPE_PY_OBJECT);
if (object != Py_None)
g_value_set_boxed (value, object);
else
g_value_set_boxed (value, NULL);
}
typedef PyObject *(*PtrToPy) (gpointer ptr,
gpointer data);
static PyObject *
slist_to_pyobject (GSList *list,
PtrToPy func,
gpointer data)
{
int i;
GSList *l;
PyObject *result;
result = PyList_New (g_slist_length (list));
for (i = 0, l = list; l != NULL; l = l->next, ++i)
{
PyObject *item = func (l->data, data);
if (!item)
{
Py_DECREF (result);
return NULL;
}
PyList_SetItem (result, i, item);
}
return result;
}
PyObject *
_moo_object_slist_to_pyobject (GSList *list)
{
return slist_to_pyobject (list, (PtrToPy) pygobject_new, NULL);
}
static PyObject *
string_to_pyobject (gpointer str)
{
if (!str)
return_RuntimeError ("got NULL string");
else
return PyString_FromString (str);
}
PyObject *
_moo_string_slist_to_pyobject (GSList *list)
{
return slist_to_pyobject (list, (PtrToPy) string_to_pyobject, NULL);
}
static PyObject *
boxed_to_pyobject (gpointer boxed,
gpointer type)
{
return pyg_boxed_new (GPOINTER_TO_SIZE (type), boxed, TRUE, TRUE);
}
PyObject *
_moo_boxed_slist_to_pyobject (GSList *list,
GType type)
{
g_return_val_if_fail (g_type_is_a (type, G_TYPE_BOXED), NULL);
return slist_to_pyobject (list, boxed_to_pyobject,
GSIZE_TO_POINTER (type));
}
PyObject *
_moo_py_object_ref (PyObject *obj)
{
Py_XINCREF (obj);
return obj;
}
void
_moo_py_object_unref (PyObject *obj)
{
Py_XDECREF (obj);
}
char *
_moo_py_err_string (void)
{
PyObject *exc, *value, *tb;
PyObject *str_exc, *str_value, *str_tb;
GString *string;
PyErr_Fetch (&exc, &value, &tb);
PyErr_NormalizeException (&exc, &value, &tb);
if (!exc)
return NULL;
string = g_string_new (NULL);
str_exc = PyObject_Str (exc);
str_value = PyObject_Str (value);
str_tb = PyObject_Str (tb);
if (str_exc)
g_string_append_printf (string, "%s\n", PyString_AS_STRING (str_exc));
if (str_value)
g_string_append_printf (string, "%s\n", PyString_AS_STRING (str_value));
if (str_tb)
g_string_append_printf (string, "%s\n", PyString_AS_STRING (str_tb));
Py_XDECREF(exc);
Py_XDECREF(value);
Py_XDECREF(tb);
Py_XDECREF(str_exc);
Py_XDECREF(str_value);
Py_XDECREF(str_tb);
return g_string_free (string, FALSE);
}
/***********************************************************************/
/* File-like object for sys.stdout and sys.stderr
*/
typedef struct {
PyObject_HEAD
GPrintFunc write_func;
} MooPyFile;
static PyObject *
_moo_py_file_close (G_GNUC_UNUSED PyObject *self)
{
return_None;
}
static PyObject *
_moo_py_file_flush (G_GNUC_UNUSED PyObject *self)
{
return_None;
}
static PyObject *
_moo_py_file_write (PyObject *self, PyObject *args)
{
char *string;
MooPyFile *file = (MooPyFile *) self;
if (!PyArg_ParseTuple (args, "s", &string))
return NULL;
if (!file->write_func)
return_RuntimeError ("no write function installed");
file->write_func (string);
return_None;
}
static PyMethodDef MooPyFile_methods[] = {
{ "close", (PyCFunction) _moo_py_file_close, METH_NOARGS, NULL },
{ "flush", (PyCFunction) _moo_py_file_flush, METH_NOARGS, NULL },
{ "write", (PyCFunction) _moo_py_file_write, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
static PyTypeObject MooPyFile_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"MooPyFile", /* tp_name */
sizeof (MooPyFile), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor) 0, /* tp_dealloc */
(printfunc) 0, /* tp_print */
(getattrfunc) 0, /* tp_getattr */
(setattrfunc) 0, /* tp_setattr */
(cmpfunc) 0, /* tp_compare */
(reprfunc) 0, /* tp_repr */
(PyNumberMethods*) 0, /* tp_as_number */
(PySequenceMethods*) 0, /* tp_as_sequence */
(PyMappingMethods*) 0, /* tp_as_mapping */
(hashfunc) 0, /* tp_hash */
(ternaryfunc) 0, /* tp_call */
(reprfunc) 0, /* tp_str */
(getattrofunc) 0, /* tp_getattro */
(setattrofunc) 0, /* tp_setattro */
(PyBufferProcs*) 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
NULL, /* Documentation string */
(traverseproc) 0, /* tp_traverse */
(inquiry) 0, /* tp_clear */
(richcmpfunc) 0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc) 0, /* tp_iter */
(iternextfunc) 0, /* tp_iternext */
MooPyFile_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
NULL, /* tp_base */
NULL, /* tp_dict */
(descrgetfunc) 0, /* tp_descr_get */
(descrsetfunc) 0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc) 0, /* tp_init */
(allocfunc) 0, /* tp_alloc */
(newfunc) 0, /* tp_new */
(freefunc) 0, /* tp_free */
(inquiry) 0, /* tp_is_gc */
NULL, NULL, NULL, NULL, NULL, NULL
};
static void
set_file (const char *name,
GPrintFunc func)
{
MooPyFile *file;
file = PyObject_New (MooPyFile, &MooPyFile_Type);
if (!file)
{
PyErr_Print ();
return;
}
file->write_func = func;
if (PySys_SetObject ((char*) name, (PyObject*) file))
PyErr_Print ();
Py_DECREF (file);
}
static void
print_func (const char *string)
{
g_print ("%s", string);
}
static void
printerr_func (const char *string)
{
g_printerr ("%s", string);
}
void
_moo_py_init_print_funcs (void)
{
static gboolean done;
if (done)
return;
done = TRUE;
if (PyType_Ready (&MooPyFile_Type) < 0)
{
g_critical ("could not init MooPyFile type");
return;
}
set_file ("stdout", print_func);
set_file ("stderr", printerr_func);
}

View File

@ -0,0 +1,92 @@
/*
* moopython/moopython-utils.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOO_PYTHON_UTILS_H
#define MOO_PYTHON_UTILS_H
#include <Python.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define MOO_TYPE_PY_OBJECT (_moo_py_object_get_type())
PyObject *_moo_py_object_ref (PyObject *obj);
void _moo_py_object_unref (PyObject *obj);
GType _moo_py_object_get_type (void) G_GNUC_CONST;
PyObject *_moo_strv_to_pyobject (char **strv);
/* result may not be freed */
int _moo_pyobject_to_strv (PyObject *obj,
char ***dest);
int _moo_pyobject_to_strv_no_null (PyObject *obj,
char ***dest);
PyObject *_moo_object_slist_to_pyobject (GSList *list);
PyObject *_moo_string_slist_to_pyobject (GSList *list);
PyObject *_moo_boxed_slist_to_pyobject (GSList *list,
GType type);
PyObject *_moo_gvalue_to_pyobject (const GValue *val);
void _moo_pyobject_to_gvalue (PyObject *object,
GValue *value);
char *_moo_py_err_string (void);
void _moo_py_init_print_funcs (void);
#define return_Obj(obj) return Py_INCREF (obj), obj
#define return_Self return_Obj (self)
#define return_None return_Obj (Py_None)
/* avoid strict aliasing warnings */
#define return_True return PyBool_FromLong (TRUE)
#define return_False return PyBool_FromLong (FALSE)
#define return_Bool(v) return PyBool_FromLong ((v) && TRUE)
#define return_Int(v) return PyInt_FromLong (v)
#define return_AttrError(msg) return PyErr_SetString (PyExc_AttributeError, msg), NULL
#define return_AttrErrorInt(msg) return PyErr_SetString (PyExc_AttributeError, msg), -1
#define return_TypeError(msg) return PyErr_SetString (PyExc_TypeError, msg), NULL
#define return_TypeErrorInt(msg) return PyErr_SetString (PyExc_TypeError, msg), -1
#define return_RuntimeError(msg) return PyErr_SetString (PyExc_RuntimeError, msg), NULL
#define return_RuntimeErrorInt(msg) return PyErr_SetString (PyExc_RuntimeError, msg), -1
#define return_ValueError(msg) return PyErr_SetString (PyExc_ValueError, msg), NULL
#define return_ValueErrorInt(msg) return PyErr_SetString (PyExc_ValueError, msg), -1
#if PY_MINOR_VERSION < 4
#define Py_InitializeEx(arg) Py_Initialize()
#define Py_IncRef _moo_Py_IncRef
#define Py_DecRef _moo_Py_DecRef
inline static void
Py_IncRef (PyObject *obj)
{
Py_XINCREF (obj);
}
inline static void
Py_DecRef (PyObject *obj)
{
Py_XDECREF (obj);
}
#endif
G_END_DECLS
#endif /* MOO_PYTHON_UTILS_H */

View File

@ -0,0 +1,44 @@
/*
* moo-mod.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
#include "moopython/pygtk/moo-pygtk.h"
#include "moopython/moopython-api.h"
#include "moopython/moopython-loader.h"
#include "mooutils/moopython.h"
void initmoo (void);
void initmoo (void)
{
if (!_moo_pygtk_init ())
return;
if (!moo_python_running() && !moo_python_api_init ())
return;
if (!moo_plugin_loader_lookup (MOO_PYTHON_PLUGIN_LOADER_ID))
{
MooPluginLoader *loader = _moo_python_get_plugin_loader ();
moo_plugin_loader_register (loader, MOO_PYTHON_PLUGIN_LOADER_ID);
_moo_python_plugin_loader_free (loader);
}
}

View File

@ -0,0 +1,194 @@
/*
* moopython-mod.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
*
* This file is part of medit. medit is free software; you can
* redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public
* License along with medit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Python.h>
#include <pygobject.h>
#include <pygtk/pygtk.h>
#include "moopython/moopython-api.h"
#include "moopython/moopython-loader.h"
#include "moopython/moopython-pygtkmod.h"
#include "mooedit/mooplugin-macro.h"
#include "mooutils/moopython.h"
#include "mooutils/mooutils-misc.h"
static gboolean
sys_path_add_dir (const char *dir)
{
PyObject *new_path, *path;
PyObject *add;
g_return_val_if_fail (dir != NULL, FALSE);
path = PySys_GetObject ("path");
if (!path)
{
PyErr_Print ();
return FALSE;
}
if (!PySequence_Check (path))
{
g_critical ("sys.path is not a sequence");
return FALSE;
}
add = PyList_New (1);
PyList_SET_ITEM (add, 0, PyString_FromString (dir));
new_path = PySequence_Concat (add, path);
Py_DECREF (add);
if (!new_path)
{
PyErr_Print ();
return FALSE;
}
if (PySys_SetObject ("path", new_path) != 0)
{
PyErr_Print ();
Py_DECREF (new_path);
return FALSE;
}
Py_DECREF (new_path);
return TRUE;
}
static void
sys_path_remove_dir (const char *dir)
{
PyObject *path;
int i, len;
gboolean found = FALSE;
g_return_if_fail (dir != NULL);
path = PySys_GetObject ("path");
if (!path)
{
PyErr_Print ();
return;
}
if (!PySequence_Check (path))
return;
len = PySequence_Size (path);
if (len < 0)
{
PyErr_Print ();
return;
}
for (i = len - 1; !found && i >= 0; --i)
{
PyObject *item = PySequence_ITEM (path, i);
if (item && PyString_CheckExact (item) &&
!strcmp (PyString_AsString (item), dir))
{
found = TRUE;
PySequence_DelItem (path, i);
}
if (PyErr_Occurred ())
PyErr_Print ();
Py_XDECREF (item);
}
}
MOO_MODULE_INIT_FUNC_DECL;
MOO_MODULE_INIT_FUNC_DECL
{
PyObject *moo_mod;
char *dlldir = NULL;
char *libdir = NULL;
if (g_getenv ("MOO_DEBUG_NO_PYTHON"))
return FALSE;
if (moo_python_running ())
return FALSE;
if (!moo_python_api_init ())
{
g_warning ("%s: oops", G_STRLOC);
return FALSE;
}
#ifdef __WIN32__
dlldir = moo_win32_get_dll_dir (MOO_PYTHON_MODULE_DLL_NAME);
#endif
if (dlldir)
{
libdir = g_build_filename (dlldir, "lib", NULL);
g_free (dlldir);
dlldir = NULL;
}
if (libdir && !sys_path_add_dir (libdir))
{
g_free (libdir);
libdir = NULL;
}
moo_mod = PyImport_ImportModule ("moo");
if (libdir)
{
sys_path_remove_dir (libdir);
g_free (libdir);
}
if (!moo_mod)
{
PyErr_Print ();
g_warning ("%s: could not import moo", G_STRLOC);
moo_python_api_deinit ();
return FALSE;
}
init_pygtk_mod ();
if (PyErr_Occurred ())
{
PyErr_Print ();
g_warning ("%s: could not import gobject", G_STRLOC);
moo_python_api_deinit ();
return FALSE;
}
reset_log_func ();
if (!moo_plugin_loader_lookup (MOO_PYTHON_PLUGIN_LOADER_ID))
{
MooPluginLoader *loader = _moo_python_get_plugin_loader ();
moo_plugin_loader_register (loader, MOO_PYTHON_PLUGIN_LOADER_ID);
_moo_python_plugin_loader_free (loader);
}
return TRUE;
}

View File

@ -0,0 +1,36 @@
DIST_SUBDIRS = pyproject
SUBDIRS = .
if MOO_ENABLE_PROJECT
SUBDIRS += pyproject
endif
moopython_pluginsdir = ${MOO_PLUGINS_DIR}
plugins_libdir = ${MOO_PLUGINS_DIR}/lib
INI_IN_IN_FILES = \
terminal.ini.in.in \
python.ini.in.in \
pycmd.ini.in.in
plugins = \
terminal.py \
python.py \
pycmd.py
moopython_plugins_DATA = \
$(INI_FILES) \
$(plugins)
plugins_lib_DATA = \
lib/pyconsole.py \
lib/insert_date_and_time.py
nobase_plugins_lib_DATA = \
medit/__init__.py \
medit/runpython.py
EXTRA_DIST += \
$(nobase_plugins_lib_DATA) \
$(plugins_lib_DATA) \
$(plugins)

View File

@ -0,0 +1,104 @@
#
# insert_date_and_time.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import gtk
import time
import moo
# List of formats is shamelessly stolen from gedit
formats = [
"%c",
"%x",
"%X",
"%x %X",
"%Y-%m-%d %H:%M:%S",
"%a %b %d %H:%M:%S %Z %Y",
"%a %b %d %H:%M:%S %Y",
"%a %d %b %Y %H:%M:%S %Z",
"%a %d %b %Y %H:%M:%S",
"%d/%m/%Y",
"%d/%m/%y",
"%D",
"%A %d %B %Y",
"%A %B %d %Y",
"%Y-%m-%d",
"%d %B %Y",
"%B %d, %Y",
"%A %b %d",
"%H:%M:%S",
"%H:%M",
"%I:%M:%S %p",
"%I:%M %p",
"%H.%M.%S",
"%H.%M",
"%I.%M.%S %p",
"%I.%M %p",
"%d/%m/%Y %H:%M:%S",
"%d/%m/%y %H:%M:%S",
]
moo.utils.prefs_new_key_string('Tools/InsertDateAndTime', '%c')
def populate_tree_view(treeview):
model = gtk.ListStore(str, str)
curtime = time.localtime()
default_iter = None
default_fmt = moo.utils.prefs_get_string('Tools/InsertDateAndTime')
for fmt in formats:
iter = model.append([time.strftime(fmt, curtime), fmt])
if default_fmt == fmt:
default_iter = iter
cell = gtk.CellRendererText()
column = gtk.TreeViewColumn(None, cell, text=0)
treeview.append_column(column)
treeview.set_model(model)
if default_iter is not None:
treeview.get_selection().select_iter(default_iter)
def get_format_from_list(treeview):
model, row = treeview.get_selection().get_selected()
fmt = model[row][1]
moo.utils.prefs_set_string('Tools/InsertDateAndTime', fmt)
return fmt
def get_format(parent=None):
window = gtk.Dialog("Select Format", parent, 0,
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
window.set_alternative_button_order([gtk.RESPONSE_ACCEPT, gtk.RESPONSE_REJECT])
window.set_size_request(250, 300)
swindow = gtk.ScrolledWindow()
treeview = gtk.TreeView()
swindow.add(treeview)
swindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
swindow.show_all()
window.vbox.pack_start(swindow)
populate_tree_view(treeview)
treeview.set_headers_visible(False)
treeview.connect('row-activated', lambda tv, path, clmn, dlg:
dlg.response(gtk.RESPONSE_ACCEPT), window)
fmt = None
if window.run() == gtk.RESPONSE_ACCEPT:
fmt = get_format_from_list(treeview)
window.destroy()
return fmt
if __name__ == '__main__':
print get_format()

View File

@ -0,0 +1,674 @@
#!/usr/bin/env python
#
# pyconsole.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
# Thanks to Geoffrey French for ideas.
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
# This module 'runs' python interpreter in a TextView widget.
# The main class is Console, usage is:
# Console(locals=None, banner=None, completer=None, use_rlcompleter=True, start_script='') -
# it creates the widget and 'starts' interactive session; see the end of
# this file. If start_script is not empty, it pastes it as it was entered from keyboard.
#
# Console has "command" signal which is emitted when code is about to
# be executed. You may connect to it using console.connect or console.connect_after
# to get your callback ran before or after the code is executed.
#
# To modify output appearance, set attributes of console.stdout_tag and
# console.stderr_tag.
#
# Console may subclass a type other than gtk.TextView, to allow syntax highlighting and stuff,
# e.g.:
# console_type = pyconsole.ConsoleType(moo.edit.TextView)
# console = console_type(use_rlcompleter=False, start_script="import moo\nimport gtk\n")
#
# This widget is not a replacement for real terminal with python running
# inside: GtkTextView is not a terminal.
# The use case is: you have a python program, you create this widget,
# and inspect your program interiors.
import gtk
import gtk.gdk as gdk
import gobject
import pango
import gtk.keysyms as _keys
import code
import sys
import keyword
import re
# commonprefix() from posixpath
def _commonprefix(m):
"Given a list of pathnames, returns the longest common leading component"
if not m: return ''
prefix = m[0]
for item in m:
for i in range(len(prefix)):
if prefix[:i+1] != item[:i+1]:
prefix = prefix[:i]
if i == 0:
return ''
break
return prefix
class _ReadLine(object):
class Output(object):
def __init__(self, console, tag_name):
object.__init__(self)
self.buffer = console.get_buffer()
self.tag_name = tag_name
def write(self, text):
pos = self.buffer.get_iter_at_mark(self.buffer.get_insert())
self.buffer.insert_with_tags_by_name(pos, text, self.tag_name)
class History(object):
def __init__(self):
object.__init__(self)
self.items = ['']
self.ptr = 0
self.edited = {}
def commit(self, text):
if text and self.items[-1] != text:
self.items.append(text)
self.ptr = 0
self.edited = {}
def get(self, dir, text):
if len(self.items) == 1:
return None
if text != self.items[self.ptr]:
self.edited[self.ptr] = text
elif self.edited.has_key(self.ptr):
del self.edited[self.ptr]
self.ptr = self.ptr + dir
if self.ptr >= len(self.items):
self.ptr = 0
elif self.ptr < 0:
self.ptr = len(self.items) - 1
try:
return self.edited[self.ptr]
except KeyError:
return self.items[self.ptr]
def __init__(self):
object.__init__(self)
self.set_wrap_mode(gtk.WRAP_CHAR)
self.modify_font(pango.FontDescription("Monospace"))
self.buffer = self.get_buffer()
self.buffer.connect("insert-text", self.on_buf_insert)
self.buffer.connect("delete-range", self.on_buf_delete)
self.buffer.connect("mark-set", self.on_buf_mark_set)
self.do_insert = False
self.do_delete = False
self.stdout_tag = self.buffer.create_tag("stdout", foreground="#006000")
self.stderr_tag = self.buffer.create_tag("stderr", foreground="#B00000")
self._stdout = _ReadLine.Output(self, "stdout")
self._stderr = _ReadLine.Output(self, "stderr")
self.cursor = self.buffer.create_mark("cursor",
self.buffer.get_start_iter(),
False)
insert = self.buffer.get_insert()
self.cursor.set_visible(True)
insert.set_visible(False)
self.ps = ''
self.in_raw_input = False
self.run_on_raw_input = None
self.tab_pressed = 0
self.history = _ReadLine.History()
self.nonword_re = re.compile("[^\w\._]")
def freeze_undo(self):
try: self.begin_not_undoable_action()
except: pass
def thaw_undo(self):
try: self.end_not_undoable_action()
except: pass
def raw_input(self, ps=None):
if ps:
self.ps = ps
else:
self.ps = ''
iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())
if ps:
self.freeze_undo()
self.buffer.insert(iter, self.ps)
self.thaw_undo()
self.__move_cursor_to(iter)
self.scroll_to_mark(self.cursor, 0.2)
self.in_raw_input = True
if self.run_on_raw_input:
run_now = self.run_on_raw_input
self.run_on_raw_input = None
self.buffer.insert_at_cursor(run_now + '\n')
def on_buf_mark_set(self, buffer, iter, mark):
if mark is not buffer.get_insert():
return
start = self.__get_start()
end = self.__get_end()
if iter.compare(self.__get_start()) >= 0 and \
iter.compare(self.__get_end()) <= 0:
buffer.move_mark_by_name("cursor", iter)
self.scroll_to_mark(self.cursor, 0.2)
def __insert(self, iter, text):
self.do_insert = True
self.buffer.insert(iter, text)
self.do_insert = False
def on_buf_insert(self, buf, iter, text, len):
if not self.in_raw_input or self.do_insert or not len:
return
buf.stop_emission("insert-text")
lines = text.splitlines()
need_eol = False
for l in lines:
if need_eol:
self._commit()
iter = self.__get_cursor()
else:
cursor = self.__get_cursor()
if iter.compare(self.__get_start()) < 0:
iter = cursor
elif iter.compare(self.__get_end()) > 0:
iter = cursor
else:
self.__move_cursor_to(iter)
need_eol = True
self.__insert(iter, l)
self.__move_cursor(0)
def __delete(self, start, end):
self.do_delete = True
self.buffer.delete(start, end)
self.do_delete = False
def on_buf_delete(self, buf, start, end):
if not self.in_raw_input or self.do_delete:
return
buf.stop_emission("delete-range")
start.order(end)
line_start = self.__get_start()
line_end = self.__get_end()
if start.compare(line_end) > 0:
return
if end.compare(line_start) < 0:
return
self.__move_cursor(0)
if start.compare(line_start) < 0:
start = line_start
if end.compare(line_end) > 0:
end = line_end
self.__delete(start, end)
def do_key_press_event(self, event, parent_type):
if not self.in_raw_input:
return parent_type.do_key_press_event(self, event)
tab_pressed = self.tab_pressed
self.tab_pressed = 0
handled = True
state = event.state & (gdk.SHIFT_MASK |
gdk.CONTROL_MASK |
gdk.MOD1_MASK)
keyval = event.keyval
if not state:
if keyval == _keys.Return:
self._commit()
elif keyval == _keys.Up:
self.__history(-1)
elif keyval == _keys.Down:
self.__history(1)
elif keyval == _keys.Left:
self.__move_cursor(-1)
elif keyval == _keys.Right:
self.__move_cursor(1)
elif keyval == _keys.Home:
self.__move_cursor(-10000)
elif keyval == _keys.End:
self.__move_cursor(10000)
elif keyval == _keys.Tab:
cursor = self.__get_cursor()
if cursor.starts_line():
handled = False
else:
cursor.backward_char()
if cursor.get_char().isspace():
handled = False
else:
self.tab_pressed = tab_pressed + 1
self.__complete()
else:
handled = False
elif state == gdk.CONTROL_MASK:
if keyval == _keys.u:
start = self.__get_start()
end = self.__get_cursor()
self.__delete(start, end)
else:
handled = False
else:
handled = False
if not handled:
return parent_type.do_key_press_event(self, event)
else:
return True
def __history(self, dir):
text = self._get_line()
new_text = self.history.get(dir, text)
if not new_text is None:
self.__replace_line(new_text)
self.__move_cursor(0)
self.scroll_to_mark(self.cursor, 0.2)
def __get_cursor(self):
return self.buffer.get_iter_at_mark(self.cursor)
def __get_start(self):
iter = self.__get_cursor()
iter.set_line_offset(len(self.ps))
return iter
def __get_end(self):
iter = self.__get_cursor()
if not iter.ends_line():
iter.forward_to_line_end()
return iter
def __get_text(self, start, end):
return self.buffer.get_text(start, end, False)
def __move_cursor_to(self, iter):
self.buffer.place_cursor(iter)
self.buffer.move_mark_by_name("cursor", iter)
def __move_cursor(self, howmany):
iter = self.__get_cursor()
end = self.__get_cursor()
if not end.ends_line():
end.forward_to_line_end()
line_len = end.get_line_offset()
move_to = iter.get_line_offset() + howmany
move_to = min(max(move_to, len(self.ps)), line_len)
iter.set_line_offset(move_to)
self.__move_cursor_to(iter)
def __delete_at_cursor(self, howmany):
iter = self.__get_cursor()
end = self.__get_cursor()
if not end.ends_line():
end.forward_to_line_end()
line_len = end.get_line_offset()
erase_to = iter.get_line_offset() + howmany
if erase_to > line_len:
erase_to = line_len
elif erase_to < len(self.ps):
erase_to = len(self.ps)
end.set_line_offset(erase_to)
self.__delete(iter, end)
def __get_width(self):
if not (self.flags() & gtk.REALIZED):
return 80
layout = pango.Layout(self.get_pango_context())
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
layout.set_text(letters)
pix_width = layout.get_pixel_size()[0]
return self.allocation.width * len(letters) / pix_width
def __print_completions(self, completions):
line_start = self.__get_text(self.__get_start(), self.__get_cursor())
line_end = self.__get_text(self.__get_cursor(), self.__get_end())
iter = self.buffer.get_end_iter()
self.__move_cursor_to(iter)
self.__insert(iter, "\n")
width = max(self.__get_width(), 4)
max_width = max([len(s) for s in completions])
n_columns = max(int(width / (max_width + 1)), 1)
col_width = int(width / n_columns)
total = len(completions)
col_length = total / n_columns
if total % n_columns:
col_length = col_length + 1
col_length = max(col_length, 1)
if col_length == 1:
n_columns = total
col_width = width / total
for i in range(col_length):
for j in range(n_columns):
ind = i + j*col_length
if ind < total:
if j == n_columns - 1:
n_spaces = 0
else:
n_spaces = col_width - len(completions[ind])
self.__insert(iter, completions[ind] + " " * n_spaces)
self.__insert(iter, "\n")
self.__insert(iter, "%s%s%s" % (self.ps, line_start, line_end))
iter.set_line_offset(len(self.ps) + len(line_start))
self.__move_cursor_to(iter)
self.scroll_to_mark(self.cursor, 0.2)
def __complete(self):
text = self.__get_text(self.__get_start(), self.__get_cursor())
start = ''
word = text
nonwords = self.nonword_re.findall(text)
if nonwords:
last = text.rfind(nonwords[-1]) + len(nonwords[-1])
start = text[:last]
word = text[last:]
completions = self.complete(word)
if completions:
prefix = _commonprefix(completions)
if prefix != word:
start_iter = self.__get_start()
start_iter.forward_chars(len(start))
end_iter = start_iter.copy()
end_iter.forward_chars(len(word))
self.__delete(start_iter, end_iter)
self.__insert(end_iter, prefix)
elif self.tab_pressed > 1:
self.freeze_undo()
self.__print_completions(completions)
self.thaw_undo()
self.tab_pressed = 0
def complete(self, text):
return None
def _get_line(self):
start = self.__get_start()
end = self.__get_end()
return self.buffer.get_text(start, end, False)
def __replace_line(self, new_text):
start = self.__get_start()
end = self.__get_end()
self.__delete(start, end)
self.__insert(end, new_text)
def _commit(self):
end = self.__get_cursor()
if not end.ends_line():
end.forward_to_line_end()
text = self._get_line()
self.__move_cursor_to(end)
self.freeze_undo()
self.__insert(end, "\n")
self.in_raw_input = False
self.history.commit(text)
self.do_raw_input(text)
self.thaw_undo()
def do_raw_input(self, text):
pass
class _Console(_ReadLine, code.InteractiveInterpreter):
def __init__(self, locals=None, banner=None,
completer=None, use_rlcompleter=True,
start_script=None):
_ReadLine.__init__(self)
code.InteractiveInterpreter.__init__(self, locals)
self.locals["__console__"] = self
self.start_script = start_script
self.completer = completer
self.banner = banner
if not self.completer and use_rlcompleter:
try:
import rlcompleter
self.completer = rlcompleter.Completer()
except ImportError:
pass
self.ps1 = ">>> "
self.ps2 = "... "
self.__start()
self.run_on_raw_input = start_script
self.raw_input(self.ps1)
def __start(self):
self.cmd_buffer = ""
self.freeze_undo()
self.thaw_undo()
self.buffer.set_text("")
if self.banner:
iter = self.buffer.get_start_iter()
self.buffer.insert_with_tags_by_name(iter, self.banner, "stdout")
if not iter.starts_line():
self.buffer.insert(iter, "\n")
def clear(self, start_script=None):
if start_script is None:
start_script = self.start_script
else:
self.start_script = start_script
self.__start()
self.run_on_raw_input = start_script
def do_raw_input(self, text):
if self.cmd_buffer:
cmd = self.cmd_buffer + "\n" + text
else:
cmd = text
saved_stdout, saved_stderr = sys.stdout, sys.stderr
sys.stdout, sys.stderr = self._stdout, self._stderr
if self.runsource(cmd):
self.cmd_buffer = cmd
ps = self.ps2
else:
self.cmd_buffer = ''
ps = self.ps1
sys.stdout, sys.stderr = saved_stdout, saved_stderr
self.raw_input(ps)
def do_command(self, code):
try:
eval(code, self.locals)
except SystemExit:
raise
except:
self.showtraceback()
def runcode(self, code):
if gtk.pygtk_version[1] < 8:
self.do_command(code)
else:
self.emit("command", code)
def exec_command(self, command):
if self._get_line():
self._commit()
self.buffer.insert_at_cursor(command)
self._commit()
def complete_attr(self, start, end):
try:
obj = eval(start, self.locals)
strings = dir(obj)
if end:
completions = {}
for s in strings:
if s.startswith(end):
completions[s] = None
completions = completions.keys()
else:
completions = strings
completions.sort()
return [start + "." + s for s in completions]
except:
return None
def complete(self, text):
if self.completer:
completions = []
i = 0
try:
while 1:
s = self.completer.complete(text, i)
if s:
completions.append(s)
i = i + 1
else:
completions.sort()
return completions
except NameError:
return None
dot = text.rfind(".")
if dot >= 0:
return self.complete_attr(text[:dot], text[dot+1:])
completions = {}
strings = keyword.kwlist
if self.locals:
strings.extend(self.locals.keys())
try: strings.extend(eval("globals()", self.locals).keys())
except: pass
try:
exec "import __builtin__" in self.locals
strings.extend(eval("dir(__builtin__)", self.locals))
except:
pass
for s in strings:
if s.startswith(text):
completions[s] = None
completions = completions.keys()
completions.sort()
return completions
def ReadLineType(t=gtk.TextView):
class readline(t, _ReadLine):
def __init__(self, *args, **kwargs):
t.__init__(self)
_ReadLine.__init__(self, *args, **kwargs)
def do_key_press_event(self, event):
return _ReadLine.do_key_press_event(self, event, t)
gobject.type_register(readline)
return readline
def ConsoleType(t=gtk.TextView):
class console_type(t, _Console):
__gsignals__ = {
'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object,)),
'key-press-event' : 'override'
}
def __init__(self, *args, **kwargs):
if gtk.pygtk_version[1] < 8:
gobject.GObject.__init__(self)
else:
t.__init__(self)
_Console.__init__(self, *args, **kwargs)
def do_command(self, code):
return _Console.do_command(self, code)
def do_key_press_event(self, event):
return _Console.do_key_press_event(self, event, t)
if gtk.pygtk_version[1] < 8:
gobject.type_register(console_type)
return console_type
ReadLine = ReadLineType()
Console = ConsoleType()
def _create_widget(start_script):
try:
import moo
console_type = ConsoleType(moo.edit.TextView)
console = console_type(banner="Hello there!",
use_rlcompleter=False,
start_script=start_script)
console.set_property("highlight-current-line", False)
editor = moo.edit.create_editor_instance()
console.set_lang_by_id("python-console")
except ImportError:
console = Console(banner="Hello there!",
use_rlcompleter=False,
start_script=start_script)
console.modify_font(pango.FontDescription("Monospace"))
return console
def _make_window(start_script="from gtk import *\n"):
window = gtk.Window()
window.set_title("pyconsole.py")
swin = gtk.ScrolledWindow()
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
window.add(swin)
console = _create_widget(start_script)
swin.add(console)
window.set_default_size(500, 400)
window.show_all()
if not gtk.main_level():
window.connect("destroy", gtk.main_quit)
gtk.main()
return console
if __name__ == '__main__':
import sys
import os
sys.path.insert(0, os.getcwd())
_make_window(sys.argv[1:] and '\n'.join(sys.argv[1:]) + '\n' or None)

View File

@ -0,0 +1,14 @@
#
# medit/__init__.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#

View File

@ -0,0 +1,85 @@
#
# medit/runpython.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import sys
import os
import re
import gtk
import moo
from moo.utils import _
if os.name == 'nt':
PYTHON_COMMAND = '"' + sys.exec_prefix + '\\pythonw.exe" -u'
else:
PYTHON_COMMAND = 'python -u'
PANE_ID = 'PythonOutput'
class Runner(object):
def __init__(self, window, python_command=PYTHON_COMMAND, pane_id=PANE_ID, pane_label=None):
self.window = window
self.python_command = python_command
self.pane_id = pane_id
self.pane_label = pane_label
def __get_output(self):
return self.window.get_pane(self.pane_id)
def __ensure_output(self):
pane = self.__get_output()
if pane is None:
label = self.pane_label or moo.utils.PaneLabel(icon_name=moo.utils.STOCK_EXECUTE,
label_text=_("Python Output"))
output = moo.edit.CmdView()
output.set_property("highlight-current-line", True)
output.set_filter(moo.edit.command_filter_create("python"))
pane = gtk.ScrolledWindow()
pane.set_shadow_type(gtk.SHADOW_ETCHED_IN)
pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
pane.add(output)
pane.show_all()
pane.output = output
self.window.add_pane(self.pane_id, pane, label, moo.utils.PANE_POS_BOTTOM)
self.window.add_stop_client(output)
return pane
def run(self, filename=None, args_string=None, working_dir=None):
pane = self.__get_output()
if pane is not None and pane.output.running():
return
if filename is None:
doc = self.window.get_active_doc()
if not doc:
return
if not doc.get_filename() or doc.get_status() & moo.edit.EDIT_MODIFIED:
if not doc.save():
return
filename = doc.get_filename()
pane = self.__ensure_output()
pane.output.clear()
self.window.paned.present_pane(pane)
if working_dir is None:
working_dir = os.path.dirname(filename)
cmd_line = self.python_command + ' "%s"' % os.path.basename(filename)
if args_string is not None:
cmd_line += ' %s' % (args_string,)
pane.output.run_command(cmd_line, working_dir)

View File

@ -0,0 +1,4 @@
[module]
type=Python
file=pycmd.py
version=@MOO_MODULE_MAJOR_VERSION@.@MOO_MODULE_MINOR_VERSION@

View File

@ -0,0 +1,96 @@
#
# pycmd.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import moo
import gobject
import gtk
from moo.utils import _
class PyCmd(moo.edit.Command):
def __init__(self, code, options):
moo.edit.Command.__init__(self)
if code and code[-1] != '\n' and code[-1] != '\r':
self.code = code + '\n'
else:
self.code = code
self.set_options(options)
def __set_variable(self, name, value, dic):
dic[name] = value
def do_run(self, ctx):
dic = {}
dic['doc'] = ctx.get_doc()
dic['window'] = ctx.get_window()
dic['buffer'] = ctx.get_doc() and ctx.get_doc().get_buffer()
dic['editor'] = moo.edit.editor_instance()
dic['moo'] = moo
ctx.foreach(self.__set_variable, dic)
buf = (ctx.get_doc() and ctx.get_doc().get_buffer()) or None
if buf is not None:
buf.begin_user_action()
exc = None
try:
exec self.code in dic
except Exception, e:
exc = e
if buf is not None:
buf.end_user_action()
if exc is not None:
raise exc
class PyCmdFactory(moo.edit.CommandFactory):
def do_create_command(self, data, options):
return PyCmd(data.get_code(), moo.edit.parse_command_options(options))
def do_create_widget(self):
swin = gtk.ScrolledWindow()
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
swin.set_shadow_type(gtk.SHADOW_ETCHED_IN)
textview = moo.edit.TextView()
swin.add(textview)
swin.show_all()
textview.set_font_from_string("Monospace")
textview.set_lang_by_id("python")
swin.textview = textview
return swin
def do_load_data(self, widget, data):
code = data.get_code()
if not code:
code = ""
elif not code.endswith("\n"):
code = code + "\n"
widget.textview.get_buffer().set_text(code)
def do_save_data(self, widget, data):
new_code = widget.textview.get_buffer().props.text or None
old_code = data.get_code() or None
if new_code != old_code:
data.set_code(new_code)
return True
else:
return False
gobject.type_register(PyCmd)
gobject.type_register(PyCmdFactory)
moo.edit.command_factory_register("python", _("Python script"), PyCmdFactory(), None, ".py")

View File

@ -0,0 +1,85 @@
INI_IN_IN_FILES = project-plugin.ini.in.in
inidir = ${MOO_PLUGINS_DIR}
ini_DATA = $(INI_FILES)
plugindir = $(inidir)/project
nobase_plugin_DATA = \
project-plugin.py \
mprj/__init__.py \
mprj/factory.py \
mprj/factory.glade \
mprj/manager.py \
mprj/project.py \
mprj/optdialog.py \
mprj/session.py \
mprj/settings.py \
mprj/simple.py \
mprj/simple.glade \
mprj/test.py \
mprj/utils.py \
mprj/utils.glade \
mprj/config/_config.py \
mprj/config/_dict.py \
mprj/config/_group.py \
mprj/config/__init__.py \
mprj/config/_item.py \
mprj/config/_setting.py \
mprj/config/_utils.py \
mprj/config/view.py \
mprj/config/_xml.py
projectsdir = $(MOO_LIB_DIR)
nobase_projects_DATA = \
projects/c.py \
projects/cproj/config.py \
projects/cproj/__init__.py \
projects/cproj/optdialog.py \
projects/cproj/parser.py \
projects/cproj/options.glade \
projects/python.py \
projects/pyproj/config.py \
projects/pyproj/__init__.py \
projects/pyproj/optdialog.py \
projects/pyproj/options.glade
EXTRA_DIST += \
$(nobase_plugin_DATA) \
$(nobase_projects_DATA)
###############################################################################
#
# mime info
#
BUILT_SOURCES += medit-mprj.xml
CLEANFILES += medit-mprj.xml
@MOO_INTLTOOL_XML_RULE@
mimedir = $(datadir)/mime
packagesdir = $(mimedir)/packages
packages_DATA = medit-mprj.xml
EXTRA_DIST += medit-mprj.xml.in
update_mime = update-mime-database $(DESTDIR)${mimedir}
if MOO_ENABLE_GENERATED_FILES
install-data-hook:
@if echo "Updating mime database... " && \
echo $(update_mime) && \
$(update_mime); \
then \
echo "Done."; \
else \
echo "*** "; \
echo "*** Mime database not updated. After install, run this:"; \
echo $(update_mime); \
echo "*** "; \
fi
uninstall-hook:
@echo "Updating mime database" && \
echo $(update_mime) && \
$(update_mime) && \
echo "Done."
endif

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-medit-project">
<sub-class-of type="application/xml"/>
<_comment>medit project</_comment>
<glob pattern="*.mprj"/>
</mime-type>
</mime-info>

View File

@ -0,0 +1,18 @@
#
# mprj/__init__.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
"""mprj - medit project plugin"""
project_version = "2.0"

View File

@ -0,0 +1,21 @@
#
# mprj/config/__init__.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
from mprj.config._config import *
from mprj.config._item import *
from mprj.config._setting import *
from mprj.config._group import *
from mprj.config._dict import *
from mprj.config._xml import *

View File

@ -0,0 +1,71 @@
#
# mprj/config/_config.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Config']
from mprj.config._group import Group, _GroupMeta
from mprj.config._xml import XMLGroup, File
class Config(Group):
__no_item_methods__ = True
# override parent's __call__ method, so Config() works as intended
class __metaclass__(_GroupMeta):
def __call__(self, *args, **kwargs):
kwargs['_do_create_instance'] = True
obj = _GroupMeta.__call__(self, *args, **kwargs)
del kwargs['_do_create_instance']
return obj
def __init__(self, file):
Group.__init__(self, 'medit-project')
if file is not None:
self.load_xml(file.root)
self.name = file.name
self.type = file.project_type
self.version = file.version
def copy(self):
copy = type(self)(None)
copy.copy_from(self)
return copy
def copy_from(self, other):
self.name = other.name
self.type = other.type
self.version = other.version
return Group.copy_from(self, other)
def load_xml(self, xml):
Group.load(self, xml)
def format(self):
return '<?xml version="1.0" encoding="UTF-8"?>\n' + \
self.get_xml().get_string()
def dump_xml(self):
return self.get_xml().get_string()
def get_xml(self):
xml = Group.save(self)
if xml:
xml = xml[0]
else:
xml = XMLGroup('medit-project')
xml.set_attr('name', self.name)
xml.set_attr('type', self.type)
xml.set_attr('version', self.version)
return xml

View File

@ -0,0 +1,198 @@
#
# mprj/config/_dict.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Dict']
from mprj.config._item import Item, create_instance
from mprj.config._xml import XMLGroup, XMLItem
from mprj.config._utils import dict_diff
def _load_instance(typ, node, id):
if issubclass(typ, Item):
obj = create_instance(typ, id)
obj.load(node)
else:
val = node.get()
# XXX
if val is None and typ is str:
obj = None
else:
obj = typ(val)
return obj
def _create_node(elm_name, attr_name, name, string):
if elm_name is not None:
node = XMLItem(elm_name, string)
node.set_attr(attr_name, name)
else:
node = XMLItem(name, string)
return node
def _save_instance(elm_name, attr_name, name, obj):
if isinstance(obj, Item):
nodes = obj.save()
if elm_name is not None:
if len(nodes) != 1:
raise NotImplementedError()
nodes[0].name = elm_name
nodes[0].set_attr(attr_name, name)
return nodes
if obj is None:
return [_create_node(elm_name, attr_name, name, None)]
else:
return [_create_node(elm_name, attr_name, name, str(obj))]
def _copy_instance(obj):
if isinstance(obj, Item):
return obj.copy()
else:
return type(obj)(obj)
def _check_type(obj, elm_type):
if obj is not None:
return isinstance(obj, elm_type)
if elm_type is str:
return True
return False
class DictBase(Item):
pass
def Dict(typ, **kwargs):
if not isinstance(typ, type):
raise TypeError('argument %s is invalid for Dict()' % (typ,))
attrs = {}
for k in kwargs:
attrs[k] = kwargs[k]
class Dict(DictBase):
__elm_type__ = typ
__item_attributes__ = attrs
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
self.__items = {}
attrs = getattr(type(self), '__item_attributes__')
if attrs.has_key('xml_elm_name'):
self.__xml_elm_name = attrs['xml_elm_name']
else:
self.__xml_elm_name = None
if self.__xml_elm_name is not None:
if attrs.has_key('xml_attr_name'):
self.__xml_attr_name = attrs['xml_attr_name']
else:
self.__xml_attr_name = 'name'
def __len__(self): return len(self.__items)
def __iter__(self): return self.__items.__iter__()
def has_key(self, key): return self.__items.has_key(key)
def __delitem__(self, key): del self.__items[key]
def __getitem__(self, key):
item = self.__items[key]
if issubclass(Dict.__elm_type__, Item):
return item.get_value()
else:
return item
def __setitem__(self, key, value):
if not _check_type(value, Dict.__elm_type__):
print 'value: ', value
print '__elm_type__: ', Dict.__elm_type__
raise TypeError('value %s is invalid for %s' % (value, self))
self.__items[key] = value
def __eq__(self, other):
return type(self) == type(other) and \
self.get_id() == other.get_id() and \
self.__items == other.__items
def __ne__(self, other):
return not self.__eq__(other)
def get_value(self):
return self
def items(self): return self.__items.items()
def keys(self): return self.__items.keys()
def copy_from(self, other):
changed = Item.copy_from(self, other)
first, common, second = dict_diff(self.__items, other.__items)
if first or second:
changed = True
for key in first:
del self[key]
for key in second:
self[key] = _copy_instance(other.__items[key])
if issubclass(Dict.__elm_type__, Item):
for key in common:
changed = self.__items[key].copy_from(other.__items[key]) or changed
else:
for key in common:
old = self.__items[key]
new = other.__items[key]
if old != new:
self.__items[key] = new
changed = True
return changed
def rename(self, old_key, new_key):
item = self[old_key]
if self.has_key(new_key):
raise KeyError('key %s already exists' % (new_key,))
self.__items[new_key] = item
del self.__items[old_key]
assert item.get_id() == old_key
item.set_id(new_key)
def load(self, node):
for c in node.children():
if self.__xml_elm_name is not None:
if c.name == self.__xml_elm_name:
if not c.has_attr(self.__xml_attr_name):
raise RuntimeError("element '%s' doesn't have '%s' attribute" % \
(c.name, self.__xml_attr_name))
key = c.get_attr(self.__xml_attr_name)
self[key] = _load_instance(Dict.__elm_type__, c, key)
else:
raise RuntimeError("unknown element '%s'" % (c.name,))
else:
self[c.name] = _load_instance(Dict.__elm_type__, c, c.name)
def cmp_nodes(self, n1, n2):
return cmp(n1.name, n2.name) or \
cmp(n1.get_attr(self.__xml_attr_name), n2.get_attr(self.__xml_attr_name))
def save(self):
nodes = []
for key in self:
if self.__xml_elm_name is not None:
nodes += _save_instance(self.__xml_elm_name, self.__xml_attr_name, key, self[key])
else:
nodes += _save_instance(None, None, key, self[key])
if nodes:
nodes.sort(self.cmp_nodes)
return [XMLGroup(self.get_id(), nodes, sort=False)]
else:
return []
return Dict

View File

@ -0,0 +1,168 @@
#
# mprj/config/_group.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Group', 'ValueNotSet']
from mprj.config._item import Item, _ItemMeta, create_instance
from mprj.config._xml import XMLGroup
from mprj.config._utils import dict_diff
class ValueNotSetType(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
instance = object.__new__(cls)
setattr(cls, 'instance', instance)
return getattr(cls, 'instance')
def __nonzero__(self):
return False
ValueNotSet = ValueNotSetType()
class _GroupMeta(_ItemMeta):
def __init__(cls, name, bases, dic):
super(_GroupMeta, cls).__init__(name, bases, dic)
items = {}
deleted = {}
if dic.has_key('__items__'):
src = dic['__items__']
for a in src:
if src[a] != 'delete':
items[a] = src[a]
else:
deleted[a] = ''
for b in bases:
if hasattr(b, '__items__'):
parent_items = getattr(b, '__items__')
for i in parent_items:
if not items.has_key(i) and not deleted.has_key(i):
items[i] = parent_items[i]
if items:
setattr(cls, '__items__', items)
class Group(Item):
__metaclass__ = _GroupMeta
def __init__(self, id, items={}, not_set=False, **kwargs):
Item.__init__(self, id, **kwargs)
self.__items = []
self.__items_dict = {}
self.__not_set = not_set
if items:
for id in items:
self.add_item(items[id], id)
if hasattr(type(self), '__items__'):
items = getattr(type(self), '__items__')
for id in items:
self.add_item(items[id], id)
def __getattr__(self, attr):
if self.has_item(attr):
return self[attr].get_value()
else:
raise KeyError("no attribute '%s' in '%s'" % (attr, self))
def __setattr__(self, name, value):
if name.startswith('_'):
Item.__setattr__(self, name, value)
else:
dic = self.__items_dict
if dic.has_key(name):
dic[name].set_value(value)
else:
Item.__setattr__(self, name, value)
def __len__(self): return len(self.__items)
def __nonzero__(self): return True
def __getitem__(self, key): return self.__items_dict[key]
def __setitem__(self, key, value):
if self.__items_dict.has_key(key):
return self.__items_dict[key].set(value)
else:
raise KeyError("no attribute '%s' in '%s'" % (key, self))
def __iter__(self):
return self.__items.__iter__()
def has_item(self, name):
return self.__items_dict.has_key(name)
def copy_from(self, other):
changed = Item.copy_from(self, other)
first, common, second = dict_diff(self.__items_dict, other.__items_dict)
if first or second:
changed = True
for id in first:
self.remove_item(id)
for id in common:
changed = self[id].copy_from(other[id]) or changed
for id in second:
self.add_item(other[id].copy())
return changed
def get_value(self):
if self.__not_set:
return None
else:
return self
def items(self): return self.__items
def keys(self): return self.__items_dict.keys()
def add_item(self, info, id=None):
if id is None:
id = info.get_id()
if self.has_item(id):
raise RuntimeError("item '%s' already exist in '%s'" % (id, self))
item = create_instance(info, id)
self.__items.append(item)
self.__items_dict[id] = item
def load(self, node):
for c in node.children():
if self.has_item(c.name):
self[c.name].load(c)
def save(self):
children = []
attrs = getattr(type(self), '__items__')
for setting in self:
children += setting.save()
if not children:
return []
return [XMLGroup(self.get_id(), children)]
def __eq__(self, other):
if type(self) == type(other):
for item in self:
if item != other[item.get_id()]:
return False
return True
else:
return False
def __ne__(self, other):
return not self.__eq__(other)

View File

@ -0,0 +1,207 @@
#
# mprj/config/_item.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Item']
from moo.utils import _
def create_instance(descr, *args, **kwargs):
if isinstance(descr, Item):
return descr
if not isinstance(descr, type) or not issubclass(descr, Item):
raise TypeError('invalid argument for create_instance: %s' % (descr,))
return descr.create_instance(*args, **kwargs)
def _create_item_class(cls, dct):
if not dct:
return cls
class ItemClass(cls):
__item_attributes__ = dct
return ItemClass
class _ItemMeta(type):
# Override __call__ so that syntax FooSetting(foo=bar)
# returns new class derived from FooSetting with __item_attributes__
# set. It makes it possible to use nicer {'id' : FooSetting(default=1)}
# syntax in Group __items__ attribute.
# If _do_create_instance keyword argument is True, then
# actually do create an instance.
def __call__(self, *args, **kwargs):
if kwargs.has_key('_do_create_instance') and \
kwargs['_do_create_instance'] is True:
del kwargs['_do_create_instance']
obj = type.__call__(self, *args, **kwargs)
kwargs['_do_create_instance'] = True
return obj
else:
dct = {}
for k in kwargs:
dct[k] = kwargs[k]
return _create_item_class(self, dct)
def __init__(cls, name, bases, dic):
super(_ItemMeta, cls).__init__(name, bases, dic)
# Add create_instace class method.
if not dic.has_key('create_instance'):
def create_instance(self, *args, **kwargs):
kwargs['_do_create_instance'] = True
obj = self(*args, **kwargs)
del kwargs['_do_create_instance']
return obj
setattr(cls, 'create_instance', classmethod(create_instance))
meta_attrs = {}
if dic.has_key('__class_attributes__'):
meta_attrs = dic['__class_attributes__']
for c in bases:
if hasattr(c, '__class_attributes__'):
m = getattr(c, '__class_attributes__')
for k in m:
meta_attrs[k] = m[k]
setattr(cls, '__class_attributes__', meta_attrs)
attrs = {}
if dic.has_key('__item_attributes__'):
attrs = dic['__item_attributes__']
for a in meta_attrs:
if dic.has_key(a):
attrs[meta_attrs[a]] = dic[a]
for c in bases:
if hasattr(c, '__item_attributes__'):
d = getattr(c, '__item_attributes__')
for k in d:
# XXX copy
if not attrs.has_key(k):
attrs[k] = d[k]
setattr(cls, '__item_attributes__', attrs)
# check basic methods
if not hasattr(cls, '__no_item_methods__') and not dic.has_key('__no_item_methods__'):
if dic.has_key('__init__') or dic.has_key('set_value'):
if not dic.has_key('copy_from'):
raise RuntimeError('Class %s does not implement copy_from()' % (cls,))
if not dic.has_key('load'):
raise RuntimeError('Class %s does not implement load()' % (cls,))
if not dic.has_key('save'):
raise RuntimeError('Class %s does not implement save()' % (cls,))
else:
def notimplemented(name):
def notimplemented(*args, **kwargs):
raise NotImplementedError('Class %s does not implement %s()' % (cls, name))
return notimplemented
# if not dic.has_key('copy_from'):
# setattr(cls, 'copy_from', notimplemented('copy_from'))
if not dic.has_key('load'):
setattr(cls, 'load', notimplemented('load'))
if not dic.has_key('save'):
setattr(cls, 'save', notimplemented('save'))
class Item(object):
__metaclass__ = _ItemMeta
__class_attributes__ = {
'__item_name__' : 'name',
'__item_description__' : 'description',
'__item_cell_types__' : 'cell_types',
'__item_visible__' : 'visible',
}
def __init__(self, id, name=None, description=None, visible=None, cell_types=None):
object.__init__(self)
self.__id = id
attrs = getattr(type(self), '__item_attributes__')
if not cell_types and attrs.has_key('cell_types'):
cell_types = attrs['cell_types']
if not isinstance(cell_types, list) and \
not isinstance(cell_types, tuple):
cell_types = [cell_types]
if not cell_types:
cell_types = []
if name is None:
if attrs.has_key('name'):
name = attrs['name']
else:
name = _(id)
if description is None:
if attrs.has_key('description'):
description = attrs['description']
else:
description = name
if visible is None:
if attrs.has_key('visible'):
visible = attrs['visible']
else:
visible = True
self.__config_cells = []
self.__name = name
self.__description = description
self.__visible = visible
self.__cell_types = cell_types
def set_id(self, new_id): self.__id = new_id
def set_name(self, name): self.__name = name
def set_description(self, description): self.__description = description
def set_visible(self, visible): self.__visible = visible
def set_cell_types(self, cell_types): self.__cell_types = cell_types
def get_id(self): return self.__id
def get_name(self): return self.__name
def get_description(self): return self.__description
def get_visible(self): return self.__visible
def get_cell_types(self): return self.__cell_types
def set_config_cells(self, cells): self.__config_cells = cells
def get_config_cells(self): return self.__config_cells
def load(self, node): raise NotImplementedError()
def save(self): raise NotImplementedError()
def get_value(self): raise NotImplementedError()
def set_value(self): raise NotImplementedError()
def copy_from(self, other):
self.__name = other.__name
self.__description = other.__description
self.__visible = other.__visible
return False
def copy(self):
copy = create_instance(type(self), self.get_id())
copy.copy_from(self)
return copy
def dump_xml(self):
nodes = self.save()
if not nodes:
return ''
if len(nodes) > 1:
return '\n'.join([n.get_string() for n in nodes])
else:
return nodes[0].get_string()
def __str__(self):
return '<%s %s>' % (type(self), self.get_id())
def __repr__(self):
return self.__str__()

View File

@ -0,0 +1,136 @@
#
# mprj/config/_setting.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Setting']
from mprj.config._item import Item, create_instance
from mprj.config._xml import XMLItem
class Setting(Item):
__class_attributes__ = {
'__item_default__' : 'default',
'__item_editable__' : 'editable',
'__item_data_type__' : 'data_type',
'__item_null_ok__' : 'null_ok',
}
def __init__(self, id, value=None, **kwargs):
Item.__init__(self, id, **kwargs)
default = None
editable = True
data_type = None
null_ok = False
attrs = getattr(type(self), '__item_attributes__')
if attrs.has_key('default'):
default = attrs['default']
if attrs.has_key('editable'):
editable = attrs['editable']
if attrs.has_key('data_type'):
data_type = attrs['data_type']
if attrs.has_key('null_ok'):
null_ok = attrs['null_ok']
elif default is None:
null_ok = True
self.__default = default
self.__value = default
self.__editable = editable
self.__data_type = data_type
self.__null_ok = null_ok
if value is None:
self.reset()
else:
self.set_value(value)
def reset(self):
self.set_value(self.__default)
def set_string(self, value):
if value is not None:
data_type = self.get_data_type()
if data_type is None:
raise NotImplementedError()
else:
value = data_type(value)
return self.set_value(value)
def check_value(self, value):
try:
self.transform_value(value)
except Exception:
return False
def transform_value(self, value):
if value is None and self.__null_ok:
return None
data_type = self.get_data_type()
if data_type is not None:
if not isinstance(value, data_type):
raise TypeError('value %s is invalid for %s' % (value, self))
else:
return value
else:
return value
def set_value(self, value):
value = self.transform_value(value)
if not self.equal(value):
self.__value = value
return True
else:
return False
def __eq__(self, other):
if isinstance(other, Setting):
return self.equal(other.get_value())
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
def get_value(self): return self.__value
def get_default(self): return self.__default
def get_editable(self): return self.__editable
def get_data_type(self): return self.__data_type
def is_default(self):
return self.equal(self.get_default())
def copy_from(self, other):
changed = Item.copy_from(self, other)
return self.set_value(other.get_value()) or changed
def equal(self, value):
return self.get_value() == value
def load(self, node):
self.set_string(node.get())
def save(self):
if not self.is_default():
value = self.get_value()
if value is not None:
value = str(value)
return [XMLItem(self.get_id(), value)]
else:
return []

View File

@ -0,0 +1,26 @@
#
# mprj/config/_utils.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
def dict_diff(dic1, dic2):
first, common, second = {}, {}, {}
for k in dic1:
if dic2.has_key(k):
common[k] = k
else:
first[k] = k
for k in dic2:
if not common.has_key(k):
second[k] = k
return first, common, second

View File

@ -0,0 +1,234 @@
#
# mprj/config/_xml.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['BadFileError', 'File']
import cgi
import xml.dom
from xml.dom.minidom import parseString
class BadFileError(Exception):
pass
class File(object):
def __init__(self, string, path=None):
self.xml = XML(string)
self.root = self.xml.root
if self.root.name != 'medit-project':
raise BadFileError('Invalid root element "%s"' % (self.root.name,))
self.path = path
self.version = self.root.get_attr('version')
self.name = self.root.get_attr('name')
self.project_type = self.root.get_attr('type')
if not self.version:
raise BadFileError('Version missing')
if not self.name:
raise BadFileError('Name missing')
if not self.project_type:
raise BadFileError('Project type missing')
_INDENT_STRING = " "
class XMLNode(object):
def __init__(self, name):
if not name:
raise ValueError()
self.name = name
self.parent = None
self.__attrs = {}
def has_attr(self, attr):
return self.__attrs.has_key(attr)
def get_attr(self, attr):
if self.__attrs.has_key(attr):
return self.__attrs[attr]
else:
return None
def set_attr(self, attr, val):
if val is None:
if self.__attrs.has_key(attr):
del self.__attrs[attr]
else:
self.__attrs[attr] = val
def load_xml(self, elm):
for i in range(elm.attributes.length):
item = elm.attributes.item(i)
self.set_attr(item.name, item.value)
def format_start(self):
s = '<' + self.name
for k in self.__attrs:
s += ' %s="%s"' % (k, cgi.escape(str(self.__attrs[k]), True))
return s
def get_string(self):
raise NotImplementedError()
def __repr__(self):
return self.get_string()
def _attributes_equal(self, other):
return self.name == other.name and \
self.__attrs == other.__attrs
class XMLGroup(XMLNode):
def __init__(self, name, children=[], sort=True):
XMLNode.__init__(self, name)
self.__children = []
self.__children_names = {}
if children:
if sort:
def cmp_nodes(n1, n2):
return cmp(n1.name, n2.name)
children = [c for c in children]
children.sort(cmp_nodes)
for c in children:
self.add_child(c)
def children(self):
return self.__children
def get_child(self, name):
if self.__children_names.has_key(name):
return self.__children_names[name]
else:
return None
def add_child(self, child, index=-1):
if not isinstance(child, XMLNode):
raise TypeError
if index < 0 or index >= len(self.__children):
self.__children.append(child)
else:
self.__children.insert(index, child)
self.__children_names[child.name] = child
child.parent = self
def remove_child(self, child):
if isinstance(child, str):
child = self.get_child(child)
if not child is None:
self.remove_child(child)
return
if self.__children_names[child.name] is child:
del self.__children_names[child.name]
self.__children.remove(child)
child.parent = None
def get_xml_elm_type(self, elm):
if len(elm.childNodes) > 1:
return XMLGroup
if not elm.childNodes:
return XMLItem
c = elm.childNodes[0]
if c.nodeType == xml.dom.Node.ELEMENT_NODE:
return XMLGroup
elif c.nodeType == xml.dom.Node.TEXT_NODE:
return XMLItem
def load_xml(self, elm):
XMLNode.load_xml(self, elm)
for c in elm.childNodes:
if c.nodeType == xml.dom.Node.ELEMENT_NODE:
t = self.get_xml_elm_type(c)
if t is XMLGroup:
child = XMLGroup(c.tagName)
self.add_child(child)
child.load_xml(c)
elif t is XMLItem:
child = XMLItem(c.tagName)
self.add_child(child)
child.load_xml(c)
def get_string(self, indent=0):
s = _INDENT_STRING * indent + self.format_start() + ">\n"
for child in self.children():
s += child.get_string(indent+1)
s += _INDENT_STRING * indent + "</%s>\n" % (self.name,)
return s
def __eq__(self, other):
if type(other) != XMLGroup:
return False
if not self._attributes_equal(other):
return False
return self.children() == other.children()
def __ne__(self, other):
return not self.__eq__(other)
class XMLItem(XMLNode):
def __init__(self, name, content=None):
XMLNode.__init__(self, name)
self.set(content)
def get(self):
return self.content
def set(self, content):
self.content = content
def get_string(self, indent=0):
s = _INDENT_STRING * indent + self.format_start()
if not self.get():
s += "/>\n"
else:
s += ">%s</%s>\n" % (cgi.escape(str(self.get())), self.name)
return s
def load_xml(self, elm):
if elm.childNodes:
self.set(elm.childNodes[0].data)
else:
self.set('')
XMLNode.load_xml(self, elm)
def __eq__(self, other):
if type(other) != XMLItem:
return False
return self._attributes_equal(other) and \
self.content == other.content
def __ne__(self, other):
return not self.__eq__(other)
class XML(object):
def __init__(self, string):
object.__init__(self)
dom = parseString(string)
self.root = XMLGroup(dom.documentElement.tagName)
self.root.load_xml(dom.documentElement)
dom.unlink()
def get_string(self):
self.sync_xml()
return self.root.get_string()
def sync_xml(self):
pass
if __name__ == "__main__":
c = XML("""<xml version="1.0">
<dir>
<text>blah</text>
</dir>
</xml>""")
print c.get_string(), '================'
print c.root.get_child('dir')

View File

@ -0,0 +1,322 @@
#
# mprj/config/_test.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import unittest
from mprj.config import *
from mprj.config._item import create_instance as item_create_instance
from mprj.config._xml import XMLItem, XMLGroup, XML
class TestItem(unittest.TestCase):
def testdescription(self):
type = Item()
self.assert_(type is Item)
def testlongdescription(self):
type = Item(default=2, value=3)
self.assert_(type is not Item)
self.assert_(issubclass(type, Item))
dct = type.__item_attributes__
self.assert_(len(dct) == 2)
self.assert_(dct['default'] == 2)
self.assert_(dct['value'] == 3)
def testcreateinstance(self):
i = Item.create_instance('id', name='blah', description='an item')
self.assert_(i.get_id() == 'id')
self.assert_(i.get_name() == 'blah')
self.assert_(i.get_description() == 'an item')
self.assert_(i.get_visible())
def testcreateinstance2(self):
i = Item.create_instance('id', visible=False)
self.assert_(i.get_id() == 'id')
self.assert_(i.get_name() == 'id')
self.assert_(i.get_description() == 'id')
self.assert_(not i.get_visible())
def testjunk(self):
# id must be specified
self.assertRaises(Exception, Item.create_instance)
# 'something' is invalid
self.assertRaises(Exception, Item.create_instance, 'blah', something=8)
class TestCreateInstance(unittest.TestCase):
def testnormal(self):
item_create_instance(Item(name='wefwef'), 'id')
item_create_instance(Item(name='wefwef', description='ewfwef'), 'id')
item_create_instance(Item, 'id')
self.assertRaises(TypeError, item_create_instance, [Item, {'name' : 'ffff'}], 'id')
def testjunk(self):
self.assertRaises(TypeError, item_create_instance, Item(name='wefwef'))
item_create_instance(Item(blah='wefwef'), 'fwef')
self.assertRaises(TypeError, item_create_instance)
self.assertRaises(TypeError, item_create_instance, 'wefef')
self.assertRaises(TypeError, item_create_instance, 1)
self.assertRaises(TypeError, item_create_instance, Item, 1)
self.assertRaises(TypeError, item_create_instance, [Item], 1)
self.assertRaises(TypeError, item_create_instance, [Item], 'dd', name='ededed')
self.assertRaises(TypeError, item_create_instance, [Item, {'name' : 'fff'}], 'dd', name='ededed')
class TestSetting(unittest.TestCase):
def testvalue2(self):
s = item_create_instance(Setting(), 'id')
self.assert_(s.get_default() is None)
self.assert_(s.get_value() is None)
s.reset()
self.assert_(s.get_value() is None)
s.copy()
def testdatatype(self):
s = item_create_instance(Setting(data_type=str), 'id')
self.assert_(s.get_default() is None)
self.assert_(s.get_value() is None)
self.assertRaises(TypeError, s.set_value, 8)
s.reset()
self.assert_(s.get_value() is None)
s.set_string('5')
self.assert_(s.get_value() == '5')
s.copy()
def testdatatype2(self):
s = item_create_instance(Setting(data_type=int), 'id')
self.assert_(s.get_default() is None)
self.assert_(s.get_value() is None)
s.set_value(8)
self.assert_(s.get_value() == 8)
self.assertRaises(TypeError, s.set_value, '8')
s.reset()
self.assert_(s.get_value() is None)
s.set_string('5')
self.assert_(s.get_value() == 5)
self.assertRaises(Exception, s.set_string, 'ewfwef')
self.assertRaises(TypeError, s.set_value, 'ewfwef')
s.copy()
def testnormal(self):
s = item_create_instance(Setting(name='name', data_type=int), '1', value=2)
self.assert_(s.get_default() is None)
self.assert_(not s.is_default())
s = item_create_instance(Setting(name='name', default=8, data_type=int), '2')
self.assert_(s.get_default() == 8)
self.assert_(s.is_default())
s = item_create_instance(Setting(name='name', default=8, data_type=int), '3', value=2)
self.assert_(s.get_default() == 8)
self.assert_(s.get_value() == 2)
self.assert_(not s.is_default())
s.copy()
def testops(self):
s1 = item_create_instance(Setting(data_type=int), 'id')
s2 = item_create_instance(Setting(data_type=int), 'id')
self.assert_(s1 == s2)
s1.set_value(5)
self.assert_(s1 != s2)
s2.set_value(5)
self.assert_(s1 == s2)
s2 = s1.copy()
self.assert_(s1 == s2)
self.assert_(s1.equal(5))
self.assert_(not s1.equal(s2))
self.assert_(not s1.equal(3))
s1.copy()
s2.copy()
def testsave(self):
s = item_create_instance(Setting(data_type=int), 'id')
self.assert_(s.save() == [])
s.set_value(5)
self.assert_(s.save() == [XMLItem('id', '5')])
s.reset()
self.assert_(s.save() == [])
s.copy()
def testsave2(self):
s = item_create_instance(Setting(data_type=str), 'id')
self.assert_(s.save() == [])
s.set_value('')
self.assert_(s.save() == [XMLItem('id', '')])
s.reset()
self.assert_(s.save() == [])
s.copy()
def testsave3(self):
s = item_create_instance(Setting(default='444', data_type=str), 'id')
self.assert_(s.save() == [])
s.set_value('fff')
self.assert_(s.save() == [XMLItem('id', 'fff')])
s.set_value('')
self.assert_(s.save() == [XMLItem('id', '')])
s.copy()
s = item_create_instance(Setting(default='444', data_type=str, null_ok=True), 'id')
s.set_value(None)
self.assert_(s.save() == [XMLItem('id', None)])
def testload(self):
s = item_create_instance(Setting(data_type=str), 'id')
node = XMLItem('id', 'fff')
s.load(node)
self.assert_(s.get_value() == 'fff')
node = XMLItem('id', None)
s.load(node)
self.assert_(s.get_value() is None)
s.copy()
def testload2(self):
s = item_create_instance(Setting(data_type=int), 'id')
node = XMLItem('id', 'fff')
self.assertRaises(ValueError, s.load, node)
node = XMLItem('id', '5')
s.load(node)
self.assert_(s.get_value() == 5)
s.copy()
class TestDict(unittest.TestCase):
def assign(self, s, key, val):
s[key] = val
def testdict(self):
s = item_create_instance(Dict(str), 'id')
self.assert_(s == s.copy())
s['blah'] = 'fwef'
self.assert_(s['blah'] == 'fwef')
s['foo'] = 'ddd'
self.assert_(s['foo'] == 'ddd')
s['foo'] = 'blah'
self.assert_(s['foo'] == 'blah')
self.assert_(s == s.copy())
self.assertRaises(Exception, self.assign, s, 'fff', 3)
def testdict2(self):
S = Setting(data_type=int, default=5)
s = item_create_instance(Dict(S), 'id')
self.assert_(s == s.copy())
s['blah'] = S.create_instance('dd')
self.assert_(s['blah'] == 5)
self.assertRaises(Exception, self.assign, s, 'fff', 5)
self.assertRaises(Exception, self.assign, s, 'fff', '44')
self.assertRaises(Exception, self.assign, s, 'fff', None)
self.assert_(s == s.copy())
def testnormal(self):
from mprj.config._dict import DictBase
self.assert_(issubclass(Dict(str), DictBase))
class TestGroup(unittest.TestCase):
def testgroup(self):
class G(Group):
__items__ = {
'foo' : Setting(data_type=int, default=8),
'bar' : Setting(data_type=int),
'baz' : Setting(data_type=str),
}
g = G.create_instance('g')
self.assert_(g == g.copy())
self.assert_(g.foo == 8)
self.assert_(g.bar is None)
self.assert_(g.baz is None)
g.foo = 2
self.assert_(g.foo == 2)
self.assert_(isinstance(g['foo'], Setting))
g.baz = '444'
self.assert_(g.baz == '444')
saved = g.save()
self.assert_(saved == [XML('<g><baz>444</baz><foo>2</foo></g>').root])
g2 = G.create_instance('g')
self.assert_(g2 != g)
g2.load(saved[0])
self.assert_(g2 == g)
def testgroup2(self):
class G1(Group):
__items__ = {
'foo' : Setting(data_type=int, default=3),
'bar' : Setting(data_type=str, default='fff'),
'baz' : Setting(data_type=str),
}
class G2(G1):
__items__ = {
'blah' : Setting(data_type=bool, default=True),
}
g1 = G1.create_instance('g')
g2 = G2.create_instance('g')
self.assert_(g1 != g2)
self.assert_(g1.foo == g2.foo)
self.assert_(g1.bar == g2.bar)
self.assert_(g1.baz == g2.baz)
self.assert_(g2.blah is True)
self.assert_(g1.copy() == g1)
self.assert_(g2.copy() == g2)
def testgroup3(self):
class G1(Group):
__items__ = {
'foo' : Setting(data_type=int, default=3),
'bar' : Setting(data_type=str, default='fff'),
'baz' : Setting(data_type=str),
}
class G2(G1):
__items__ = {
'blah' : Setting(data_type=bool, default=True),
}
class G3(Group):
__items__ = {
'foo' : G1,
'bar' : G1,
'baz' : G2,
}
g = G3.create_instance('g')
self.assert_(g.foo == g.bar)
self.assert_(g.copy() == g)
class TestConfig(unittest.TestCase):
def testconfig(self):
class C(Config):
__items__ = {
'variables' : Dict(str),
'variables2' : Dict(str, xml_elm_name='item', xml_attr_name='id'),
'project_dir' : Setting(data_type=str),
'stuff' : Dict(str)
}
f = File("""<medit-project version="2.0" name="Foo" type="Simple">
<variables>
<foo>bar</foo>
</variables>
<variables2>
<item id="foo">bar</item>
</variables2>
<project_dir>.</project_dir>
<stuff>
<kff>ddd</kff>
</stuff>
</medit-project>""")
c = C(f)
self.assert_(len(c.items()) == 4)
self.assert_(c.project_dir == '.')
self.assert_(len(c.stuff) == 1)
self.assert_(c.stuff['kff'] == 'ddd')
self.assert_(c.variables['foo'] == 'bar')
self.assert_(c.variables2['foo'] == 'bar')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,456 @@
#
# mprj/config/view.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
""" configview.py: TreeView column and cell renderers for settings """
import gtk
import gobject
import pango
from moo.utils import _
import mprj.config
""" TreeView column containing settings """
class Column(gtk.TreeViewColumn):
def __init__(self, *args, **kwargs):
gtk.TreeViewColumn.__init__(self, *args, **kwargs)
self.__column = 0
self.__cells = {}
def __add_group(self, group):
for item in group:
if isinstance(item, mprj.config.Group):
self.__add_group(item)
else:
self.__create_cell(item)
def set_group(self, group):
self.__add_group(group)
def __create_cell(self, item):
if not item.get_visible():
return
cell_types = item.get_cell_types()
key = '+'.join([str(ct) for ct in cell_types])
cells = self.__cells.get(key, [])
if not self.__cells.has_key(key):
for ct in cell_types:
cell = gobject.new(ct, xalign=0)
cell._set_column(self.__column)
self.pack_start(cell)
self.set_cell_data_func(cell, cell.cell_data_func, self.__column)
cells.append(cell)
self.__cells[key] = cells
item.set_config_cells(cells)
def set_model(self, model):
for k in self.__cells:
for c in self.__cells[k]:
c._set_model(model)
""" TreeView containing settings """
class View(gtk.TreeView):
def __init__(self, group):
gtk.TreeView.__init__(self)
self.set_property('headers_visible', False)
self.__group = group.copy()
self.__create_model()
self.column_name = gtk.TreeViewColumn()
cell = gtk.CellRendererText()
self.column_name.pack_start(cell)
self.column_name.set_cell_data_func(cell, self.__name_data_func)
self.append_column(self.column_name)
self.column_data = Column(self.__group, 0)
self.column_data.set_model(self.get_model())
self.append_column(self.column_data)
def get_group(self):
return self.__group
def __create_model(self):
need_tree = False
for item in self.__group:
if isinstance(item, mprj.config.Group):
need_tree = True
break
if need_tree:
model = self.__create_tree()
else:
model = self.__create_list()
self.set_model(model)
def __create_tree(self):
tree = gtk.TreeStore(object)
def append(model, group, parent):
for item in self.__group:
iter = (parent and model.get_iter(parent)) or None
iter = model.append(iter, [item])
if isinstance(item, mprj.Config.Group):
new_parent = model.get_path(iter)
append(model, item, new_parent)
append(tree, self.__group, None)
return tree
def __create_list(self):
list = gtk.ListStore(object)
for item in self.__group:
list.append([item])
return list
def __name_data_func(self, column, cell, model, iter):
setting = model.get_value(iter, 0)
cell.set_property('text', setting.get_name())
class DictView(gtk.TreeView):
def __init__(self):
gtk.TreeView.__init__(self)
self.dct = None
self.column_name = gtk.TreeViewColumn(_('Name'))
self.column_name.set_resizable(True)
self.cell_name = gtk.CellRendererText()
self.column_name.pack_start(self.cell_name, False)
self.append_column(self.column_name)
self.column_name.set_cell_data_func(self.cell_name, self.name_data_func)
self.cell_name.set_property('editable', True)
self.cell_name.connect('edited', self.name_edited)
self.cell_name.connect('editing-started', self.editing_started, 0)
self.column_value = gtk.TreeViewColumn(_('Value'))
self.column_value.set_resizable(True)
self.cell_value = gtk.CellRendererText()
self.column_value.pack_start(self.cell_value, False)
self.append_column(self.column_value)
self.column_value.set_cell_data_func(self.cell_value, self.value_data_func)
self.cell_value.set_property('editable', True)
self.cell_value.connect('edited', self.value_edited)
self.cell_value.connect('editing-started', self.editing_started, 1)
def set_dict(self, dct):
self.dct = dct
store = gtk.ListStore(object)
self.set_model(store)
if dct is not None:
keys = dct.keys()
keys.sort()
for key in keys:
store.append([[key, dct[key]]])
store.append([[None, None]])
def name_data_func(self, column, cell, model, iter):
data = model.get_value(iter, 0)
if data[0] is None:
cell.set_property('text', _('new...'))
cell.set_property('style', pango.STYLE_ITALIC)
# cell.set_property('foreground', 'grey')
else:
cell.set_property('text', data[0])
cell.set_property('style', pango.STYLE_NORMAL)
# cell.set_property('foreground', 'black')
def editing_started(self, cell, entry, path, ind):
model = self.get_model()
iter = model.get_iter(path)
data = model.get_value(iter, 0)
if data[ind] is None:
entry.set_text('')
def name_edited(self, cell, path, text):
if not text:
return
model = self.get_model()
iter = model.get_iter(path)
if iter is None:
return
data = model.get_value(iter, 0)
old_key = data[0]
old_val = data[1]
new_key = text
if old_key == new_key:
return
if self.dct.has_key(new_key):
raise KeyError()
if old_val is None:
old_val = ''
self.dct[new_key] = old_val
if old_key is not None:
del self.dct[old_key]
new_data = [new_key, self.dct[new_key]]
model.set_value(iter, 0, new_data)
if old_key is None:
model.append([[None, None]])
def value_data_func(self, column, cell, model, iter):
data = model.get_value(iter, 0)
if data[1] is None:
cell.set_property('text', _('click to edit...'))
cell.set_property('style', pango.STYLE_ITALIC)
# cell.set_property('foreground', 'grey')
else:
cell.set_property('text', data[1])
cell.set_property('style', pango.STYLE_NORMAL)
# cell.set_property('foreground', 'black')
def value_edited(self, cell, path, text):
model = self.get_model()
iter = model.get_iter(path)
if iter is None:
return
data = model.get_value(iter, 0)
if data[1] == text:
return
if data[0] is not None:
self.dct[data[0]] = text
data = [data[0], self.dct[data[0]]]
else:
if not text:
text = None
data = [data[0], text]
model.set_value(iter, 0, data)
def delete_activated(self, item, path):
model = self.get_model()
iter = model.get_iter(path)
if not iter:
return
data = model.get_value(iter, 0)
del self.dct[data[0]]
model.remove(iter)
def do_button_press_event(self, event):
if event.button != 3:
return gtk.TreeView.do_button_press_event(self, event)
pos = self.get_path_at_pos(int(event.x), int(event.y))
if pos is None:
return gtk.TreeView.do_button_press_event(self, event)
model = self.get_model()
if model is None:
return gtk.TreeView.do_button_press_event(self, event)
iter = model.get_iter(pos[0])
data = model.get_value(iter, 0)
if data[0] is None:
return gtk.TreeView.do_button_press_event(self, event)
self.get_selection().select_iter(iter)
menu = gtk.Menu()
item = gtk.MenuItem(_("Delete"), False)
item.show()
item.connect('activate', self.delete_activated, pos[0])
menu.add(item)
menu.popup(None, None, None, event.button, event.time)
def apply(self):
pass
class GroupView(gtk.TreeView):
def __init__(self):
gtk.TreeView.__init__(self)
self.items = None
self.column_name = gtk.TreeViewColumn()
self.column_name.set_resizable(True)
self.cell_name = gtk.CellRendererText()
self.column_name.pack_start(self.cell_name, False)
self.append_column(self.column_name)
self.column_name.set_cell_data_func(self.cell_name, self.name_data_func)
self.column_value = Column()
self.column_value.set_resizable(True)
self.append_column(self.column_value)
self.hidden_column = gtk.TreeViewColumn()
self.hidden_column.set_visible(False)
self.append_column(self.hidden_column)
def set_group(self, group):
self.column_value.set_group(group)
self.__set_items(group.items())
def __set_items(self, items):
need_tree = False
for i in items:
if i.get_visible() and isinstance(i, mprj.config.Group):
need_tree = True
break
self.items = items
store = gtk.TreeStore(object)
self.set_model(store)
if need_tree:
self.set_expander_column(self.column_name)
else:
self.set_expander_column(self.hidden_column)
def append(store, items, parent):
for item in items:
iter = (parent and model.get_iter(parent)) or None
iter = store.append(iter, [item])
if isinstance(item, mprj.config.Group):
new_parent = store.get_path(iter)
append(store, item.items(), new_parent)
append(store, items, None)
self.column_value.set_model(store)
def name_data_func(self, column, cell, model, iter):
item = model.get_value(iter, 0)
cell.set_property('text', item.get_name())
# def value_data_func(self, column, cell, model, iter):
# item = model.get_value(iter, 0)
# if isinstance(item, mprj.config.Group):
# cell.set_property('text', None)
# cell.set_property('editable', False)
# else:
# cell.set_property('text', item.get_value())
# cell.set_property('editable', True)
# def value_edited(self, cell, path, text):
# model = self.get_model()
# iter = model.get_iter(path)
# if iter is None:
# return
# item = model.get_value(iter, 0)
# item.set_string(text)
def apply(self):
pass
class Entry(gtk.Entry):
def __init__(self):
gtk.Entry.__init__(self)
self.setting = None
def set_setting(self, setting):
self.setting = setting
if setting is not None:
self.set_text(setting.get_value() or "")
else:
self.set_text("")
def apply(self):
if self.setting is not None:
self.setting.set_string(self.get_text())
gobject.type_register(Column)
gobject.type_register(View)
gobject.type_register(DictView)
gobject.type_register(GroupView)
gobject.type_register(Entry)
""" _CellMeta: metaclass for all settings cell renderers """
def _cell_data_func(dummy, column, cell, model, iter, index):
item = model.get_value(iter, index)
if not cell in item.get_config_cells():
cell.set_property('visible', False)
else:
cell.set_property('visible', True)
cell.set_data(item)
def _set_private(clsname, obj, attr, value):
setattr(obj, "_%s%s" % (clsname, attr), value)
class _CellMeta(gobject.GObjectMeta):
def __init__(cls, name, bases, dic):
super(_CellMeta, cls).__init__(name, bases, dic)
if not dic.has_key('_set_column'):
def set_column(cell, column):
_set_private(name, cell, '__column', column)
setattr(cls, '_set_column', set_column)
if not dic.has_key('_set_model'):
def set_model(cell, model):
_set_private(name, cell, '__model', model)
setattr(cls, '_set_model', set_model)
if not dic.has_key('cell_data_func'):
setattr(cls, 'cell_data_func', _cell_data_func)
gobject.type_register(cls)
""" CellText: text renderer """
class CellText(gtk.CellRendererText):
__metaclass__ = _CellMeta
def set_data(self, data):
self.set_property('text', data.get_string())
self.set_property('editable', data.get_editable())
def do_edited(self, path, text):
model = self.__model
setting = model.get_value(model.get_iter(path), self.__column)
setting.set_string(text)
def CellTextN(idx):
""" CellText: text renderer """
class CellTextN(gtk.CellRendererText):
__metaclass__ = _CellMeta
def set_data(self, data):
self.set_property('text', data.get_value()[idx])
self.set_property('editable', data.get_editable())
def do_edited(self, path, text):
model = self.__model
setting = model.get_value(model.get_iter(path), self.__column)
value = list(setting.get_value())
value[idx] = text
setting.set_value(value)
return CellTextN
""" CellToggle: toggle renderer """
class CellToggle(gtk.CellRendererToggle):
__metaclass__ = _CellMeta
def set_data(self, data):
self.set_property('active', data.get_bool())
self.set_property('activatable', data.get_editable())
def do_toggled(self, path):
model = self.__model
setting = model.get_value(model.get_iter(path), self.__column)
setting.set_value(not setting.get_bool())

View File

@ -0,0 +1,252 @@
<?xml version="1.0"?>
<glade-interface>
<requires-version lib="gtk+" version="2.12"/>
<widget class="GtkDialog" id="dialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">New Project</property>
<property name="default_width">400</property>
<property name="default_height">300</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkVBox" id="page">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Project _type&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">type</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="type">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Properties&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">3</property>
<property name="n_columns">3</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkLabel" id="file">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Project file:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Project _name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">name</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">_Location:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">location</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="location">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkButton" id="location_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">...</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="cancel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="ok">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-ok</property>
<property name="use_stock">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">-5</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,180 @@
#
# mprj/factory.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import os
import gtk
import gobject
import moo
from moo.utils import _, N_
import mprj.utils
class Factory(object):
def __init__(self, name, template = None, project_type = None):
object.__init__(self)
self.name = name
self.template = template
self.project_type = project_type
def create(self, proj_info):
if not self.template:
raise NotImplementedError("Missing template")
content = self.template % proj_info.get_subst_dict()
file = open(os.path.join(proj_info.dir, proj_info.file), 'w')
file.write(content)
file.close()
class ProjectInfo(object):
def __init__(self, factory, dir, file, name):
object.__init__(self)
self.factory = factory
self.dir = dir
self.file = file
self.name = name
def get_subst_dict(self):
return { 'project_name': self.name,
}
_COLUMN_TEXT = 0
_COLUMN_FACTORY = 1
class _Wizard(object):
def __setup_type_list(self, factories, xml):
store = gtk.ListStore(str, object)
for f in factories:
store.append([f.name, f])
treeview = xml.w_type
treeview.set_model(store)
cell = gtk.CellRendererText()
column = gtk.TreeViewColumn(None, cell, text=_COLUMN_TEXT)
treeview.append_column(column)
treeview.get_selection().select_path('0')
def __check_sensitivity(self):
sensitive = self.xml.w_name.get_text() != '' and \
self.xml.w_location.get_text() != ''
self.xml.w_dialog.set_response_sensitive(gtk.RESPONSE_OK, sensitive)
def __update_file_label(self):
if self.xml.w_name.get_text() != '' and self.xml.w_location.get_text() != '':
d, f = self.__get_project_file()
self.xml.w_file.set_text(os.path.join(d, f))
else:
self.xml.w_file.set_text('')
def __name_changed(self, *whatever):
self.__check_sensitivity()
self.__update_file_label()
def __location_changed(self, *whatever):
self.__check_sensitivity()
self.__update_file_label()
def __location_button_clicked(self, *whatever):
path = moo.utils.file_dialogp(self.xml.w_dialog,
moo.utils.FILE_DIALOG_OPEN_DIR,
self.xml.w_location.get_text(),
_("Choose Folder"),
mprj.utils.prefs_key('new_project_dir'))
if path:
self.xml.w_location.set_text(path)
def __get_project_file(self):
dir = self.xml.w_location.get_text()
file = ''
for c in self.xml.w_name.get_text():
if c in "/":
c = '_'
file += c
file += '.mprj'
return [dir, file]
def ask(self, factories, window):
glade_file = os.path.join(os.path.dirname(__file__), "factory.glade")
xml = moo.utils.glade_xml_new_from_file(glade_file, domain=moo.utils.GETTEXT_PACKAGE)
self.xml = xml
self.__setup_type_list(factories, xml)
xml.w_location.set_text(os.path.expanduser('~'))
xml.w_location_button.connect('clicked', self.__location_button_clicked)
xml.w_name.connect('changed', self.__name_changed)
xml.w_location.connect('changed', self.__location_changed)
dialog = xml.w_dialog
dialog.set_response_sensitive(gtk.RESPONSE_OK, False)
dialog.set_transient_for(window)
try:
while 1:
if dialog.run() != gtk.RESPONSE_OK:
return None
d, f = self.__get_project_file()
if os.path.lexists(d) and not os.path.isdir(d):
moo.utils.error_dialog(dialog, '%s is not a directory' % (d,))
continue
if os.path.exists(os.path.join(d, f)):
if not moo.utils.overwrite_file_dialog(dialog, f, d):
continue
if os.path.exists(d) and not os.access(d, os.W_OK):
moo.utils.error_dialog(dialog, '%s is not writable' % (d,))
continue
if not os.path.exists(d):
try:
os.mkdir(d)
except Exception, e:
moo.utils.error_dialog(dialog, 'Could not create directory %s' % (d,), str(e))
continue
model, iter = xml.w_type.get_selection().get_selected()
factory = model.get_value(iter, _COLUMN_FACTORY)
pi = ProjectInfo(factory, d, f, xml.w_name.get_text())
return pi
finally:
dialog.destroy()
def run(self, factories, window):
pi = self.ask(factories, window)
if pi is None:
return None
try:
pi.factory.create(pi)
except Exception, e:
moo.utils.error_dialog(window, 'Could not create project', str(e))
return None
return os.path.join(pi.dir, pi.file)
def new_project(project_types, window):
factories = []
for pt in project_types:
factory = None
ft = getattr(pt, '__factory__', None)
if ft is not None:
factory = ft()
else:
ft = getattr(pt, '__factory_template__', None)
if ft:
factory = Factory(pt.__factory_name__, ft, pt)
if factory is not None:
factories.append(factory)
if not factories:
return None
w = _Wizard()
return w.run(factories, window)

View File

@ -0,0 +1,338 @@
#
# mprj/manager.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import moo
import sys
import os, os.path
import gobject
from mprj.config import File
from mprj.simple import SimpleProject
import mprj.utils
import mprj.factory
from mprj.utils import print_error, format_error
from moo.utils import _, N_
moo.utils.prefs_new_key('Plugins/Project/last', str, None, moo.utils.PREFS_STATE)
moo.utils.prefs_new_key('Plugins/Project/last_dir', str, None, moo.utils.PREFS_STATE)
# moo.utils.prefs_new_key_string('Plugins/Project/last', None)
# moo.utils.prefs_new_key_string('Plugins/Project/last_dir', None)
class _ProjectStore(object):
def __init__(self):
object.__init__(self)
self.projects = {}
def add(self, name, project):
if self.projects.has_key(name):
raise RuntimeError("Project '%s' already registered" % (name,))
self.projects[name] = project
def remove(self, name):
if not self.projects.has_key(name):
raise RuntimeError("Project '%s' not registered" % (name,))
del self.projects[name]
def get(self, name):
if not self.projects.has_key(name):
raise RuntimeError("Project '%s' not registered" % (name,))
return self.projects[name]
class _OpenRecent(object):
def __init__(self, mgr):
object.__init__(self)
self.mgr = mgr
def __call__(self, window):
action = moo.utils.MenuAction("OpenRecentProject", _("Open Recent Project"))
action.set_property('display-name', _("Open Recent Project"))
action.set_mgr(self.mgr.recent_list.get_menu_mgr())
moo.utils.bind_bool_property(action, "sensitive",
self.mgr.recent_list, "empty",
True)
return action
class Manager(object):
def __init__(self, project):
object.__init__(self)
self.init(project)
def init(self, project):
editor = moo.edit.editor_instance()
editor.set_property("allow-empty-window", True)
editor.set_property("single-window", True)
moo.utils.window_class_add_action(moo.edit.EditWindow, "NewProject",
display_name=_("New Project"),
label=_("New Project..."),
stock_id=moo.utils.STOCK_NEW_PROJECT,
callback=self.new_project_cb)
moo.utils.window_class_add_action(moo.edit.EditWindow, "OpenProject",
display_name=_("Open Project"),
label=_("Open Project"),
stock_id=moo.utils.STOCK_OPEN_PROJECT,
callback=self.open_project_cb)
moo.utils.window_class_add_action(moo.edit.EditWindow, "ProjectOptions",
display_name=_("Project _Options"),
label=_("Project Options"),
stock_id=moo.utils.STOCK_PROJECT_OPTIONS,
callback=self.project_options_cb)
moo.utils.window_class_add_action(moo.edit.EditWindow, "CloseProject",
display_name=_("Close Project"),
label=_("Close Project"),
stock_id=moo.utils.STOCK_CLOSE_PROJECT,
callback=self.close_project_cb)
self.__init_project_types()
self.project_to_open = project
self.project = None
self.window = None
self.recent_list = moo.utils.HistoryList("ProjectManager")
self.recent_list.connect("activate_item", self.recent_item_activated)
moo.utils.window_class_add_action(moo.edit.EditWindow,
"OpenRecentProject",
factory=_OpenRecent(self))
xml = editor.get_ui_xml()
self.merge_id = xml.new_merge_id()
xml.insert_markup_after(self.merge_id, "Editor/Menubar",
"View", """
<item name="Project" _label="%s">
<item action="NewProject"/>
<item action="OpenProject"/>
<item action="OpenRecentProject"/>
<separator/>
<item action="ProjectOptions"/>
<separator/>
<item action="CloseProject"/>
<separator/>
</item>
""" % (N_("_Project"),))
def deinit(self):
self.close_project(True)
for a in ["NewProject", "OpenProject", "CloseProject",
"ProjectOptions", "OpenRecentProject"]:
moo.utils.window_class_remove_action(moo.edit.EditWindow, a)
editor = moo.edit.editor_instance()
editor.get_ui_xml().remove_ui(self.merge_id)
self.merge_id = 0
del self.project_types
def recent_item_activated(self, recent_list, item, whatever):
try:
self.open_project(self.window, item.data)
except Exception, e:
self.bad_project(self.window, item.data, e)
self.recent_list.remove(item.data)
def attach_win(self, window):
if self.project:
self.__set_title_prefix(self.project.name)
else:
self.__set_title_prefix(None)
self.window = window
self.window.connect('close', self.close_window)
action = self.window.get_action("CloseProject")
if action:
action.set_property("sensitive", False)
action = self.window.get_action("ProjectOptions")
if action:
action.set_property("visible", self.project is not None)
if not self.project:
project = self.project_to_open
self.project_to_open = None
if not project:
project = moo.utils.prefs_get_string("Plugins/Project/last")
if not project:
project = os.path.join(moo.utils.get_user_data_dir(), "default.mprj")
if project and os.path.exists(project):
try:
self.open_project(self.window, project)
except Exception, e:
self.bad_project(self.window, project, e)
self.recent_list.remove(project)
def __set_title_prefix(self, prefix):
editor = moo.edit.editor_instance()
editor.set_app_name(prefix or "medit")
def detach_win(self, window):
self.close_project(True)
self.__set_title_prefix(None)
self.window = None
def new_project_cb(self, window):
try:
self.new_project(window)
except Exception, e:
mprj.utils.oops(window, e)
def open_project_cb(self, window):
filename = moo.utils.file_dialogp(parent=window, title=_("Open Project"),
prefs_key="Plugins/Project/last_dir")
if not filename:
return
try:
self.open_project(window, filename)
except Exception, e:
self.bad_project(window, filename, e)
def bad_project(self, parent, filename, error):
moo.utils.error_dialog(parent, _("Could not open project '%s'") % (filename,), str(error))
def fixme(self, parent, msg):
moo.utils.warning_dialog(parent, "FIXME", str(msg))
def close_window(self, window):
return not self.close_project(False)
def project_options_cb(self, window):
if self.project:
self.project.options_dialog(window)
else:
self.fixme(window, "disable Close Project command")
def close_project_cb(self, window):
if self.project:
if self.close_project(False):
moo.utils.prefs_set_string("Plugins/Project/last", None)
else:
self.fixme(window, "disable Close Project command")
""" new_project """
def new_project(self, window):
if not self.close_project(False):
return
filename = mprj.factory.new_project(self.project_types.projects.values(), window)
if filename:
self.open_project(window, filename)
if self.project:
self.project.options_dialog(window)
""" open_project """
def open_project(self, window, filename):
if not self.close_project(False):
return
f = open(filename)
file = File(f.read())
f.close()
if file.version != mprj.project_version:
moo.utils.error_dialog(window, _("Could not open project '%s'") % (filename,),
_("Invalid project version %s") % (file.version,))
return
file.path = filename
project_type = self.project_types.get(file.project_type)
config_type = getattr(project_type, '__config__')
config = config_type(file)
self.project = project_type(window, config, file)
self.project.load()
self.__set_title_prefix(self.project.name)
self.recent_list.add_filename(filename)
moo.utils.prefs_set_string("Plugins/Project/last", filename)
close = self.window.get_action("CloseProject")
options = self.window.get_action("ProjectOptions")
if close:
close.set_property("sensitive", True)
if options:
options.set_property("visible", True)
""" close_project """
def close_project(self, force=False):
if not self.project:
return True
try:
if not self.project.close() and not force:
return False
except Exception, e:
mprj.utils.oops(self.window, e)
try:
self.project.unload()
except Exception, e:
mprj.utils.oops(self.window, e)
self.project = None
if self.window:
close = self.window.get_action("CloseProject")
options = self.window.get_action("ProjectOptions")
if close:
close.set_property("sensitive", False)
if close:
options.set_property("visible", False)
self.__set_title_prefix(None)
return True
def __read_project_file(self, path):
try:
dic = {'__name__' : '__project__', '__builtins__' : __builtins__}
execfile(path, dic)
if not dic.has_key('__project__'):
print "File %s doesn't define __project__ attribute" % (path,)
elif not dic.has_key('__project_type__'):
print "File %s doesn't define __project_type__ attribute" % (path,)
elif not dic.has_key('__project_version__'):
print "File %s doesn't define __project_version__ attribute" % (path,)
elif dic['__project_version__'] != mprj.project_version:
print "In file %s: version %s does not match current version %s" % (
path, dic['__project_version__'], mprj.project_version)
else:
self.project_types.add(dic['__project_type__'], dic['__project__'])
except Exception, e:
print_error(e)
def __init_project_types(self):
self.project_types = _ProjectStore()
self.project_types.add("Simple", SimpleProject)
dirs = list(moo.utils.get_data_subdirs("projects", moo.utils.DATA_LIB))
dirs = filter(lambda d: os.path.isdir(d), dirs)
dirs.reverse()
if not dirs:
return
saved_path = sys.path
sys.path = list(dirs) + list(saved_path)
for d in dirs:
try:
if not os.path.isdir(d):
continue
files = os.listdir(d)
for f in files:
path = os.path.join(d, f)
if os.path.isfile(path):
self.__read_project_file(path)
except:
print_error()
sys.path = saved_path

View File

@ -0,0 +1,89 @@
#
# mprj/optdialog.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import gobject
import os.path
import moo
from moo.utils import _
dir = os.path.dirname(__file__)
def _init_page(page, page_id, config, glade_file):
cls = page.__class__
xml = moo.utils.GladeXML(moo.utils.GETTEXT_PACKAGE)
xml.map_id(page_id, cls)
types = getattr(cls, '__types__', {})
for id in types:
xml.map_id(id, types[id])
glade_file = open(glade_file)
try:
xml.fill_widget(page, glade_file.read(), page_id)
assert xml.get_widget(page_id) is page
finally:
glade_file.close()
label = getattr(cls, '__label__', None)
if label is not None:
page.set_property('label', label)
page.xml = xml
page.config = config
page.widgets = [xml.get_widget(k) for k in types]
return page
class ConfigPage(moo.utils.PrefsPage):
def __init__(self, page_id, config, glade_file):
moo.utils.PrefsPage.__init__(self)
_init_page(self, page_id, config, glade_file)
def do_init(self):
pass
def do_apply(self):
for widget in self.widgets:
widget.apply()
class Dialog(moo.utils.PrefsDialog):
def __init__(self, project, title=_('Project Options')):
moo.utils.PrefsDialog.__init__(self, title)
self.project = project
self.config_copy = project.config.copy()
def do_apply(self):
moo.utils.PrefsDialog.do_apply(self)
self.project.config.copy_from(self.config_copy)
self.project.save_config()
# print '============================='
# print self.config_copy.dump_xml()
# print '============================='
# print self.project.config.dump_xml()
# print '============================='
gobject.type_register(ConfigPage)
gobject.type_register(Dialog)

View File

@ -0,0 +1,102 @@
#
# mprj/project.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
"""Project class - the base class for all project types.
All project types subclass (or are method-compatible with) Project.
When project is loaded, the following happens:
1) The project file is parsed and appropriate project type is found.
2) Config instance is created using the project type's 'config' attribute.
3) Instance of this type is created with the editor window and config
as constructor arguments.
3) If no exception raised so far, project's load() method is called without
arguments. It's responsible for initializing gui, loading session, etc.
Note, only __init__ method may (must in case of errors) raise exceptions.
Project *must* handle errors well, otherwise gui may be left in inconsistent
state. E.g. presenting a dialog saying "Could not load session file" is fine
(though annoying), but raising OSError on trying to read nonexistant file is
not.
The closing sequence is the following:
1) Project's close() method is called. It's responsible for asking user if he
wants to save his files, saving session, etc. If it returns False, it means
user changed his mind and project is not closed. Otherwise,
2) project's unload() method is called. It must remove actions it installed,
unload plugins it loaded, etc., i.e. revert the editor state to the original.
After unload() is called, the project instance is considered dead, and not used
anymore.
"""
import moo
import os.path
class Project(object):
"""Base project type.
Project types must satisfy the following requirements:
1) The class must have 'config' attribute, which is the type of
config used in this project.
2) __init__ must have the same signature: __init__(window, file).
3) Implement all the public methods of Project class (or just subclass it).
"""
def __init__(self, window, config, file):
object.__init__(self)
self.window = window
self.config = config
self.name = file.name
self.filename = os.path.abspath(file.path)
self.topdir = os.path.dirname(self.filename)
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
if xml is not None:
self.merge_id = xml.new_merge_id()
self.actions = []
self.panes = []
def add_action(self, id, **kwargs):
moo.utils.window_class_add_action(moo.edit.EditWindow, id, **kwargs)
self.actions.append(id)
def init_ui(self):
pass
def deinit_ui(self):
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
xml.remove_ui(self.merge_id)
for a in self.actions:
moo.utils.window_class_remove_action(moo.edit.EditWindow, a)
if self.window:
for p in self.panes:
self.window.remove_pane(p)
def load(self):
self.init_ui()
def close(self):
return True
def unload(self):
self.deinit_ui()

View File

@ -0,0 +1,96 @@
#
# mprj/session.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
from mprj.config._xml import XML, XMLGroup, XMLItem
import moo
import os
import mprj.utils
class Session(object):
def __init__(self, data=None):
object.__init__(self)
self.__file_selector_dir = None
self.__docs = []
self.__active = None
if data:
if isinstance(data, moo.edit.EditWindow):
self.__load_from_window(data)
else:
file = open(data)
contents = file.read()
file.close()
self.__parse(contents)
def attach(self, window):
editor = moo.edit.editor_instance()
# saved_silent = editor.get_property("silent")
# editor.set_property("silent", True)
for doc in self.__docs:
if os.path.exists(doc):
editor.open_file(window, None, doc)
# editor.set_property("silent", saved_silent)
if self.__active is not None:
doc = window.get_nth_doc(self.__active)
if doc:
window.set_active_doc(doc)
def save(self, filename):
mprj.utils.save_file(filename, self.__format())
def get_file_selector_dir(self):
return self.__file_selector_dir
def set_file_selector_dir(self, path):
self.__file_selector_dir = path
def __format(self):
root = XMLGroup('medit-session')
for d in self.__docs:
root.add_child(XMLItem('doc', d))
if self.__active is not None:
root.add_child(XMLItem('active', str(self.__active)))
if self.__file_selector_dir is not None:
root.add_child(XMLItem('file-selector', self.__file_selector_dir))
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + \
root.get_string()
def __parse(self, string):
xml = XML(string)
if xml.root.name != 'medit-session':
raise RuntimeError("Invalid root element name '%s'" % (xml.root.name,))
for node in xml.root.children():
if node.name == 'doc':
self.__parse_doc(node)
elif node.name == 'active':
self.__active = int(node.get())
elif node.name == 'file-selector':
self.__file_selector_dir = node.get()
else:
raise RuntimeError("Uknown element '%s'" % (node.name,))
def __parse_doc(self, node):
self.__docs.append(node.get())
def __load_from_window(self, window):
docs = window.list_docs()
active = window.get_active_doc()
for d in docs:
if d.get_filename():
self.__docs.append(d.get_filename())
if d is active:
self.__active = len(self.__docs) - 1

View File

@ -0,0 +1,110 @@
#
# mprj/settings.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
""" settings.py: basic Setting subclasses """
from mprj.config import Setting, Group, Dict, Item
from mprj.config.view import *
from mprj.config._xml import XMLItem, XMLGroup
def _cmp_nodes(n1, n2):
return (n1.name < n2.name and -1) or (n1.name > n2.name and 1) or 0
class String(Setting):
__item_cell_types__ = CellText
def transform_value(self, value):
if value is None or isinstance(value, str):
return value
if isinstance(value, unicode):
return str(value)
raise TypeError('value %s of type %s is invalid for %s', value, type(value), self)
def get_string(self):
return self.get_value()
def set_string(self, text):
self.set_value(text)
Filename = String
class Command(Setting):
__item_cell_types__ = [CellTextN(1), CellTextN(0)]
def copy_from(self, other):
return Setting.copy_from(self, other)
def set_value(self, value):
if len(value) != 2:
raise ValueError("invalid Command value %s" % (value,))
return Setting.set_value(self, value)
def load(self, node):
cmd = node.get_child('cmd').get()
working_dir = node.get_child('working_dir').get()
return self.set_value([working_dir, cmd])
def save(self):
if not self.is_default():
value = self.get_value()
items = [XMLItem('working_dir', value[0]), XMLItem('cmd', value[1])]
return [XMLGroup(self.get_id(), items)]
else:
return []
class Bool(Setting):
__item_data_type__ = bool
__item_cell_types__ = CellToggle
def get_bool(self):
return self.get_value()
def set_string(self, text):
self.set_value(bool(text))
class Int(Setting):
__item_data_type__ = int
__item_cell_types__ = CellText
def get_int(self):
return self.get_value()
def check_value(self, value):
try:
value = int(value)
return True
except:
return False
def set_string(self, text):
self.set_value(int(text))
if __name__ == '__main__':
import gtk
import gobject
window = gtk.Window()
window.set_size_request(300,200)
window.connect('destroy', gtk.main_quit)
group = Group.create_instance('ddd')
s = String.create_instance('blah', value='111')
group.add_item(s)
group.blah = '8'
print s.get_value()
print s is group.blah
group.add_item(String.create_instance('foo', value='foofoofoofoofoofoofoofoo'))
group.add_item(Bool.create_instance('fff', value=True))
view = View(group)
window.add(view)
window.show_all()
gtk.main()

View File

@ -0,0 +1,169 @@
<?xml version="1.0"?>
<glade-interface>
<requires-version lib="gtk+" version="2.12"/>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="page">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkButton" id="dir_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">...</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">_Name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">name</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="name">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Project _directory:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">dir</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="dir">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Variables&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="vars">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_clickable">True</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,196 @@
#
# mprj/simple.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import gobject
import os.path
import tempfile
import moo
from moo.utils import _
from mprj.project import Project
from mprj.config import Config, Dict, Group
from mprj.config.view import *
from mprj.settings import Filename
from mprj.utils import print_error
from mprj.session import Session
import mprj.optdialog
import mprj.utils
class GeneralSettings(Group):
__items__ = {
'vars' : Dict(str, name=_('Variables'), xml_elm_name='var'),
}
__item_name__ = _('General settings')
class SimpleConfig(Config):
__items__ = {
'general': GeneralSettings
}
class SimpleProject(Project):
__config__ = SimpleConfig
def __init__(self, *args, **kwargs):
Project.__init__(self, *args, **kwargs)
self.__file_selector_dir = None
self.filesel = None
self.filesel_merge_id = 0
self.__filesel_cb_id = 0
self.__filesel_destroy_cb_id = 0
def __filesel_cb(self, filesel, *whatever):
self.__file_selector_dir = filesel.get_property('current-directory')
def __filesel_destroy_cb(self, filesel):
self.filesel = None
self.__filesel_cb_id = None
self.__filesel_destroy_cb_id = None
def __setup_file_selector(self):
plugin = moo.edit.plugin_lookup('FileSelector')
if plugin:
try:
self.filesel = plugin.call_method('get-widget', self.window)
if self.filesel:
last_dir = self.__file_selector_dir
if last_dir and not os.path.isdir(last_dir):
last_dir = None
if not last_dir:
last_dir = self.topdir
self.filesel.chdir(last_dir)
self.__filesel_cb_id = self.filesel.connect('notify::current-directory', self.__filesel_cb)
self.__filesel_destroy_cb_id = self.filesel.connect('destroy', self.__filesel_destroy_cb)
except:
print_error()
def init_ui(self):
Project.init_ui(self)
def deinit_ui(self):
if self.__filesel_cb_id:
self.filesel.disconnect(self.__filesel_cb_id)
self.filesel.disconnect(self.__filesel_destroy_cb_id)
self.__filesel_cb_id = 0
self.__filesel_destroy_cb_id = 0
if self.filesel and self.filesel_merge_id:
xml = self.filesel.get_ui_xml()
xml.remove_ui(self.filesel_merge_id)
self.filesel = None
self.filesel_merge_id = 0
Project.deinit_ui(self)
def load(self):
Project.load(self)
self.load_session()
def close(self):
self.save_session()
self.save_config()
return self.window.close_all()
def get_session_file(self):
return os.path.join(self.topdir, '.' + \
os.path.basename(self.filename) + '.session')
def load_session(self):
try:
file = self.get_session_file()
if os.path.exists(file):
session = Session(file)
session.attach(self.window)
self.__file_selector_dir = session.get_file_selector_dir()
else:
self.__file_selector_dir = self.topdir
self.__setup_file_selector()
except:
print_error()
def save_session(self):
try:
file = self.get_session_file()
session = Session(self.window)
session.set_file_selector_dir(self.__file_selector_dir)
session.save(file)
except Exception, e:
moo.utils.error_dialog(self.window, 'Could not save session',
'Could not save file %s: %s' % (file, str(e)))
def save_config(self):
content = self.config.format()
try:
mprj.utils.save_file(self.filename, content)
except Exception, e:
moo.utils.error_dialog(self.window, 'Could not save project file',
'Could not save file %s: %s' % (self.filename, str(e)))
def options_dialog(self, window):
dialog = self.create_options_dialog()
dialog.run(window)
def create_options_dialog(self):
return None
class ConfigPage(mprj.optdialog.ConfigPage):
__label__ = _("General")
__types__ = {'vars': DictView, 'name': Entry}
def __init__(self, config):
mprj.optdialog.ConfigPage.__init__(self, "page", config,
os.path.join(os.path.dirname(__file__), "simple.glade"))
def do_init(self):
mprj.optdialog.ConfigPage.do_init(self)
self.xml.w_vars.set_dict(self.config.general.vars)
def do_apply(self):
mprj.optdialog.ConfigPage.do_apply(self)
gobject.type_register(ConfigPage)
if __name__ == '__main__':
from mprj.config import File
s1 = """
<medit-project name="moo" type="Simple" version="2.0">
<general>
<vars>
<foo>bar</foo>
<blah>bom</blah>
</vars>
</general>
</medit-project>
"""
c = SimpleConfig(File(s1))
s2 = str(c.get_xml())
print s2
c = SimpleConfig(File(s2))
s3 = str(c.get_xml())
assert s2 == s3

View File

@ -0,0 +1,15 @@
#
# mprj/test.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#

View File

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<glade-interface>
<requires-version lib="gtk+" version="2.12"/>
<widget class="GtkDialog" id="entry_dialog">
<property name="border_width">5</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label">Enter text</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">gtk-ok</property>
<property name="use_stock">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">-5</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,213 @@
#
# mprj/utils.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import moo
import traceback
import sys
import os
import gtk
import re
import tempfile
import shutil
def _expand(command, dic):
if isinstance(command, str) or isinstance(command, unicode):
working_dir = ''
cmd = command
else:
working_dir = command[0]
cmd = command[1]
while 1:
new_working_dir = re.sub(r'\$\(([a-zA-Z_]\w*)\)', r'%(\1)s', working_dir) % dic
new_cmd = re.sub(r'\$\(([a-zA-Z_]\w*)\)', r'%(\1)s', cmd) % dic
if new_working_dir == working_dir and new_cmd == cmd:
return [new_working_dir, new_cmd]
working_dir = new_working_dir
cmd = new_cmd
def expand_command(command, vars, filename, top_srcdir, top_builddir=None):
dic = get_file_paths(filename, top_srcdir, top_builddir)
if vars:
for v in vars:
dic[v] = vars[v]
return _expand(command, dic)
def get_file_paths(filename, top_srcdir, top_builddir=None):
top_srcdir = os.path.abspath(top_srcdir)
top_builddir = (top_builddir is None and top_srcdir) or \
os.path.abspath(top_builddir)
if filename:
filename = os.path.abspath(filename)
basename = os.path.basename(filename)
base, ext = os.path.splitext(basename)
ext = ext[1:]
srcdir = os.path.dirname(filename)
if srcdir == top_srcdir:
builddir = top_builddir
elif os.path.commonprefix([top_srcdir, srcdir]) == top_srcdir:
builddir = os.path.join(top_builddir, srcdir[len(top_srcdir) + 1:])
else:
print "can't get builddir for", filename
builddir = ''
else:
filename, basename = '', ''
base, ext = '', ''
srcdir, builddir = '', ''
return {
'top_srcdir' : top_srcdir,
'top_builddir' : top_builddir,
'srcdir' : srcdir,
'builddir' : builddir,
'filename' : filename,
'basename' : basename,
'base' : base,
'ext' : ext,
}
def implement_me(window, what):
moo.utils.warning_dialog(window, "IMPLEMENT ME", str(what))
def oops(window, error):
moo.utils.error_dialog(window, "OOPS", format_error(error))
def print_error(error=None):
print >> sys.stderr, format_error(error)
def format_error(error=None):
if error:
return str(error) + "\n" + \
"".join(traceback.format_exception(*sys.exc_info()))
else:
return "".join(traceback.format_exception(*sys.exc_info()))
def entry_dialog(parent=None, label=None, entry_content=None, title=None):
glade_file = os.path.join(os.path.dirname(__file__), "utils.glade")
xml = moo.utils.glade_xml_new_from_file(glade_file, root='entry_dialog',
domain=moo.utils.GETTEXT_PACKAGE)
xml.w_entry_dialog.set_title(title)
if parent:
parent = parent.get_toplevel()
xml.w_entry_dialog.set_transient_for(parent)
if label:
xml.w_label.set_text(label)
else:
xml.w_label.hide()
if entry_content:
xml.w_entry.set_text(entry_content)
retval = None
if xml.w_entry_dialog.run() == gtk.RESPONSE_OK:
retval = xml.w_entry.get_text()
xml.w_entry_dialog.destroy()
return retval
def error_dialog(text, secondary_text=None, parent=None):
moo.utils.error_dialog(parent, text, secondary_text)
def question_dialog(text, secondary_text=None, default_ok=False, parent=None):
if parent:
parent = parent.get_toplevel()
dlg = gtk.MessageDialog(parent, 0, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL)
dlg.set_property('text', text)
dlg.set_property('secondary_text', secondary_text)
if default_ok:
dlg.set_default_response(gtk.RESPONSE_OK)
else:
dlg.set_default_response(gtk.RESPONSE_CANCEL)
response = dlg.run()
dlg.destroy()
return response == gtk.RESPONSE_OK
def prefs_key(name):
return 'MProject/' + name
def save_file(filename, contents):
f = FileSaver(filename)
f.write(contents)
f.close()
class FileSaver(object):
def __init__(self, filename):
object.__init__(self)
self.tmp_file = None
self.tmp_name = None
self.filename = None
self.closed = True
basename = os.path.basename(filename)
dirname = os.path.dirname(filename)
tmp_fd, tmp_name = tempfile.mkstemp('', '.' + basename + '-', dirname, True)
self.tmp_file = os.fdopen(tmp_fd, 'w')
self.tmp_name = tmp_name
self.filename = filename
self.closed = False
def close(self):
if not self.closed:
self.closed = True
try:
self.tmp_file.close()
shutil.move(self.tmp_name, self.filename)
except Exception, e:
self.__cleanup()
raise e
def __cleanup(self):
if self.tmp_file:
try:
self.tmp_file.close()
except:
pass
if self.tmp_name:
try:
os.remove(self.tmp_name)
except:
pass
def flush(self):
return self.tmp_file.flush()
def fileno(self):
return self.tmp_file.fileno()
def isatty(self):
return False
def seek(self, offset, whence = 0):
return self.tmp_file.seek(offset, whence)
def tell(self):
return self.tmp_file.tell()
def truncate(self, size = 0):
return self.tmp_file.truncate(size)
def write(self, string):
return self.tmp_file.write(string)
def writelines(self, sequence):
return self.tmp_file.writelines(sequence)
if __name__ == '__main__':
print expand_command(['$(builddir)', 'make $(base).o'],
None,
'/blah/project/subdir/file.c',
'/blah/project',
'/blah/project/build')
print expand_command(['$(top_builddir)', '$(make)'],
{'make' : 'make'},
None,
'/blah/project',
'/blah/project/build')

View File

@ -0,0 +1,13 @@
[module]
type=Python
file=project/project-plugin.py
version=@MOO_MODULE_MAJOR_VERSION@.@MOO_MODULE_MINOR_VERSION@
[plugin]
id=ProjectManager
_name=Project Manager
_description=Project manager
author=Yevgen Muntyan <muntyan@tamu.edu>
version=@MOO_VERSION_UNQUOTED@
enabled=false
visible=false

View File

@ -0,0 +1,43 @@
#
# project-plugin.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import moo
import sys
import traceback
import gobject
from mprj.manager import Manager
class __plugin__(moo.edit.Plugin):
__gproperties__ = { 'project' : (str, 'project to open', 'project to open', None, gobject.PARAM_READWRITE) }
def do_set_property(self, prop, value):
self.project_to_open = value
def do_init(self):
project = None
if hasattr(self, "project_to_open"):
project = self.project_to_open
self.mgr = Manager(project)
return True
def do_deinit(self):
self.mgr.deinit()
del self.mgr
def do_attach_win(self, window):
self.mgr.attach_win(window)
def do_detach_win(self, window):
self.mgr.detach_win(window)

View File

@ -0,0 +1,291 @@
#
# c.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '..'))
import gtk
import moo
import os.path
import gobject
import mprj.utils
from mprj.simple import SimpleProject
from mprj.utils import print_error
from moo.utils import _, N_
import cproj.config
from cproj.config import CConfig
from cproj.parser import parse_make_error
from cproj.optdialog import Dialog as OptionsDialog
_STOCK_BUILD = moo.utils.STOCK_BUILD
_STOCK_COMPILE = moo.utils.STOCK_COMPILE
_STOCK_EXECUTE = moo.utils.STOCK_EXECUTE
_STOCK_PROJECT_OPTIONS = moo.utils.STOCK_PROJECT_OPTIONS
_BUILD_PANE_ID = "CProjectBuild"
_OUTPUT_PANE_ID = "CProjectOutput"
_CMD_BUILD = 'build'
_CMD_COMPILE = 'compile'
_CMD_CONFIGURE = 'configure'
_CMD_AUTOGEN = 'autogen'
_CMD_CLEAN = 'clean'
_CMD_DISTCLEAN = 'distclean'
_CMD_EXECUTE = 'execute'
_CMD_INSTALL = 'install'
class CProject(SimpleProject):
__config__ = CConfig
__factory_name__ = "C"
__factory_template__ = cproj.config.factory_template
class DoCmd(object):
def __init__(self, obj, *args):
object.__init__(self)
self.obj = obj
self.args = args
def __call__(self, window):
return self.obj.do_command(window, *self.args)
def init_ui(self):
SimpleProject.init_ui(self)
self.panes.extend([_BUILD_PANE_ID, _OUTPUT_PANE_ID])
commands = [
["Build", _("Build Project"), _STOCK_BUILD, "F8", _CMD_BUILD],
["Compile", _("Compile File"), _STOCK_COMPILE, "F9", _CMD_COMPILE],
["RunConfigure", _("Run Configure"), None, None, _CMD_CONFIGURE],
["RunAutogen", _("Run autogen.sh"), None, None, _CMD_AUTOGEN],
["Clean", _("Clean Project"), None, None, _CMD_CLEAN],
["Distclean", _("Distclean"), None, None, _CMD_DISTCLEAN],
["Execute", _("Execute Program"), _STOCK_EXECUTE, "<shift>F9", _CMD_EXECUTE],
["Install", _("Install"), None, "<shift><ctrl>I", _CMD_INSTALL],
]
for c in commands:
self.add_action("CProject" + c[0],
display_name=c[1], label=c[1],
stock_id=c[2], default_accel=c[3],
callback=CProject.DoCmd(self, c[4]))
self.add_action("CProjectBuildConfiguration",
factory=_BuildConfigurationActionFactory(self))
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
xml.insert_markup_after(self.merge_id, "Editor/Menubar",
"Project", """
<item name="Build" _label="%s">
<item action="CProjectBuild"/>
<item action="CProjectCompile"/>
<item action="CProjectRunConfigure"/>
<item action="CProjectRunAutogen"/>
<separator/>
<item action="CProjectInstall"/>
<separator/>
<item action="CProjectClean"/>
<item action="CProjectDistclean"/>
<separator/>
<item action="CProjectExecute"/>
</item>
""" % (N_("_Build"),))
xml.insert_markup(self.merge_id, "Editor/Toolbar/BuildToolbar",
0, """
<item action="CProjectBuild"/>
<item action="CProjectExecute"/>
<separator/>
""")
xml.insert_markup_before(self.merge_id,
"Editor/Menubar/Project", "ProjectOptions",
"""
<separator/>
<item action="CProjectBuildConfiguration"/>
""")
def get_build_pane(self, window):
pane = window.get_pane(_BUILD_PANE_ID)
if not pane:
label = moo.utils.PaneLabel(icon_name=_STOCK_BUILD,
label_text=_("Build Messages"))
output = moo.edit.CmdView()
window.add_stop_client(output)
if 1:
output.set_property("highlight-current-line", True)
output.set_wrap_mode(gtk.WRAP_NONE)
else:
output.set_property("highlight-current-line", False)
output.set_wrap_mode(gtk.WRAP_CHAR)
output.set_filter(moo.edit.command_filter_create('make'))
pane = gtk.ScrolledWindow()
pane.set_shadow_type(gtk.SHADOW_ETCHED_IN)
pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
pane.add(output)
pane.show_all()
pane.output = output
window.add_pane(_BUILD_PANE_ID, pane, label, moo.utils.PANE_POS_BOTTOM)
return pane
def get_output_pane(self, window):
pane = window.get_pane(_OUTPUT_PANE_ID)
if not pane:
label = moo.utils.PaneLabel(icon_name=_STOCK_EXECUTE,
label_text=_("Output"))
output = moo.edit.CmdView()
window.add_stop_client(output)
output.set_property("highlight-current-line", False)
output.set_wrap_mode(gtk.WRAP_CHAR)
pane = gtk.ScrolledWindow()
pane.set_shadow_type(gtk.SHADOW_ETCHED_IN)
pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
pane.add(output)
pane.show_all()
pane.output = output
window.add_pane(_OUTPUT_PANE_ID, pane, label, moo.utils.PANE_POS_BOTTOM)
return pane
def get_file_path(self, file):
if os.path.exists(file):
return file
bd = self.config.get_build_dir(self.topdir)
f = os.path.join(bd, file)
if os.path.exists(f):
return f
f = os.path.join(self.topdir, file)
if os.path.exists(f):
return f
return None
def save_all(self, window):
docs = window.list_docs()
for d in docs:
if d.get_filename() and d.get_status() & moo.edit.EDIT_MODIFIED:
d.save()
def do_command(self, window, cmd):
try:
self.before_command(window, cmd) and \
self.exec_command(window, cmd) and \
self.after_command(window, cmd)
except Exception, e:
mprj.utils.oops(window, e)
def before_command(self, window, cmd):
self.save_all(window)
return True
def after_command(self, window, cmd):
return True
def __cmd_execute(self, window):
exe = self.config.get_exe(self.topdir)
assert exe
pane = self.get_output_pane(window)
pane.output.clear()
window.paned.present_pane(pane)
pane.output.run_command(exe)
return True
def __cmd_simple(self, cmd, filename, window):
try:
working_dir, command = self.config.get_command(cmd, filename, self.topdir)
except Exception, e:
print_error(e)
return False
pane = self.get_build_pane(window)
pane.output.clear()
window.paned.present_pane(pane)
pane.output.run_command(command, working_dir)
pane.output.add_filter_dirs([self.topdir])
return True
def exec_command(self, window, cmd):
if cmd == _CMD_EXECUTE:
return self.__cmd_execute(window)
if cmd in [_CMD_BUILD, _CMD_INSTALL, _CMD_CONFIGURE,
_CMD_AUTOGEN, _CMD_CLEAN, _CMD_DISTCLEAN]:
return self.__cmd_simple(cmd, None, window)
if cmd in [_CMD_COMPILE]:
doc = self.window.get_active_doc()
filename = doc and doc.get_filename()
if not filename:
return False
return self.__cmd_simple(cmd, filename, window)
mprj.utils.implement_me(window, "Command " + cmd)
return False
def create_options_dialog(self):
return OptionsDialog(self)
def create_configurations_menu(self):
menu = gtk.Menu()
group = None
for name in sorted(self.config.configurations.keys()):
item = gtk.RadioMenuItem(group, name)
group = item
item.set_data('conf_name', name)
item.show()
if name == self.config.active:
item.set_active(True)
item.connect('toggled', self.conf_toggled, name)
menu.add(item)
return menu
def conf_toggled(self, item, name):
if not item.get_active() or not self.config.active \
or item.get_data('conf_name') == self.config.active:
return
self.config.set_active_conf(item.get_data('conf_name'))
self.save_config()
def apply_config(self):
action = self.window.get_action("CProjectBuildConfiguration")
for p in action.get_proxies():
if isinstance(p, gtk.MenuItem):
p.set_submenu(self.create_configurations_menu())
class _BuildConfigurationActionFactory(object):
def __init__(self, project):
object.__init__(self)
self.project = project
def __call__(self, window):
action = gobject.new(moo.utils.Action,
name="CProjectBuildConfiguration",
label="Build Configuration",
no_accel="True")
action.project = self.project
action.connect('connect-proxy', self.connect_proxy)
return action
def connect_proxy(self, action, menuitem):
menuitem.set_submenu(self.project.create_configurations_menu())
__project__ = CProject
__project_type__ = "C"
__project_version__ = "2.0"

View File

@ -0,0 +1,15 @@
#
# cproj/__init__.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#

View File

@ -0,0 +1,342 @@
#
# cproj/config.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import os.path
import moo
from moo.utils import _
from mprj.utils import expand_command
from mprj.settings import *
from mprj.simple import SimpleProject, SimpleConfig
from mprj.config._xml import XMLItem, XMLGroup
class MakeOptions(Group):
__items__ = {
'cmd' : String(default='make'),
'args' : String(null_ok=True),
'vars' : Dict(str, xml_elm_name='var')
}
__item_name__ = _('Make options')
class ConfigureOptions(Group):
__items__ = {
'args' : String(name=_('Configure arguments')),
'vars' : Dict(str, name=_('Environment variables'), xml_elm_name='var'),
}
__item_name__ = _('Configure options')
class Commands(Group):
__items__ = {
'build' : Command(default=['$(top_builddir)', '$(make)']),
'compile' : Command(default=['$(builddir)', '$(make) $(base).lo']),
'configure' : Command(default=['$(top_builddir)', '$(configure_vars) $(top_srcdir)/configure $(configure_args)']),
'autogen' : Command(default=['$(top_builddir)', '$(configure_vars) $(top_srcdir)/autogen.sh $(configure_args)']),
'clean' : Command(default=['$(top_builddir)', '$(make) clean']),
'distclean' : Command(default=['$(top_builddir)', '$(make) distclean']),
'install' : Command(default=['$(top_builddir)', '$(make) install']),
}
__item_name__ = _('Build commands')
RUN_FROM_BUILD_DIR = 0
RUN_FROM_EXE_DIR = 1
class RunFrom(Setting):
__item_name__ = _('Run from')
__item_default__ = RUN_FROM_BUILD_DIR
def equal(self, value):
if value is None:
value = 0
return Setting.equal(self, value)
def set_string(self, value):
raise RuntimeError()
def check_value(self, value):
return value in [RUN_FROM_BUILD_DIR, RUN_FROM_EXE_DIR] or \
(isinstance(value, str) and value != '')
def load(self, node):
type_s = node.get_attr('type')
if type_s == 'build-dir':
return self.set_value(RUN_FROM_BUILD_DIR)
elif type_s == 'exe-dir':
return self.set_value(RUN_FROM_EXE_DIR)
elif type_s == 'dir':
return self.set_value(node.get())
else:
raise RuntimeError()
def save(self):
if self.is_default():
return []
value = self.get_value()
if value in [RUN_FROM_BUILD_DIR, RUN_FROM_EXE_DIR]:
dir = None
else:
dir = value
item = XMLItem(self.get_id(), dir)
if value == RUN_FROM_BUILD_DIR:
item.set_attr('type', 'build-dir')
elif value == RUN_FROM_EXE_DIR:
item.set_attr('type', 'exe-dir')
else:
item.set_attr('type', 'dir')
return [item]
class RunOptions(Group):
__items__ = {
'run_from' : RunFrom,
'exe' : String(name=_('Executable')),
'args' : String(name=_('Arguments')),
'vars' : Dict(str, xml_elm_name='var')
}
__item_name__ = _('Run options')
class BuildConfiguration(Group):
__items__ = {
'build_dir' : String(name=_('Build directory')),
'configure' : ConfigureOptions
}
__item_name__ = _('Build configuration')
def copy_from(self, other):
self.name = other.name
return Group.copy_from(self, other)
def load(self, node):
self.name = node.get_attr('name')
Group.load(self, node)
class CConfig(SimpleConfig):
__items__ = {
'run' : RunOptions,
'make' : MakeOptions,
'configurations' : Dict(BuildConfiguration, xml_elm_name='configuration'),
'active' : String,
'commands' : Commands
}
def load_xml(self, xml):
SimpleConfig.load_xml(self, xml)
if not len(self.configurations):
raise RuntimeError("No configurations defined")
if self.active:
if self.active not in self.configurations.keys():
raise RuntimeError("Invalid configuration %s" % (self.active,))
else:
self.active = self.configurations.keys()[0]
def set_active_conf(self, name):
if self.active == name:
return
if not self.configurations.has_key(self.active):
raise RuntimeError("no configuration named '%s'" % (name,))
self.active = name
def get_active_conf(self):
if len(self.configurations) == 0:
raise RuntimeError("no configurations")
if not self.configurations.has_key(self.active):
return self.configurations.items()[0][1]
else:
return self.configurations[self.active]
def add_conf(self, name, old_name=None):
if self.configurations.has_key(name):
raise KeyError("configuration %s already exists" % (name,))
if old_name and not self.configurations.has_key(old_name):
raise KeyError("no configuration %s" % (old_name,))
c = BuildConfiguration(name, _do_create_instance=True)
if old_name:
c.copy_from(self.configurations[old_name])
c.name = name
self.configurations[name] = c
return c
def rename_conf(self, old_name, new_name):
self.configurations.rename(old_name, new_name)
self.configurations[new_name].name = new_name
def delete_conf(self, name):
was_active = (name == self.active)
del self.configurations[name]
if was_active:
if len(self.configurations) != 0:
self.active = self.configurations.keys()[0]
else:
self.active = None
def expand_env(self, vars):
string = ''
if vars:
for v in vars:
string += '%s="%s" ' % (v, vars[v])
return string
def __get_make(self, suffix=None):
mo = self.make
env = self.expand_env(mo.vars)
cmd = mo.cmd or 'make'
args = (mo.args and ' ' + mo.args) or ''
suffix = (suffix and ' ' + suffix) or ''
return '%s%s%s%s' % (env, cmd, args, suffix)
def get_make(self):
return self.__get_make()
def get_make_install(self):
return self.__get_make("install")
def get_exe(self, top_dir):
ro = self.run
env = self.expand_env(ro.vars)
args = ro.args or ''
builddir = self.get_build_dir(top_dir)
exe = ro.exe
if ro.run_from == RUN_FROM_EXE_DIR:
working_dir = os.path.join(builddir, os.path.dirname(exe))
exe = "./" + os.path.basename(exe)
elif ro.run_from == RUN_FROM_BUILD_DIR:
working_dir = builddir
exe = os.path.join("./", exe)
else:
working_dir = ro.run_from
if not os.path.isabs(exe):
exe = os.path.join(builddir, exe)
return "cd '%s' && %s%s %s" % (working_dir, env, exe, args)
def get_build_dir(self, top_dir):
conf = self.get_active_conf()
build_dir = conf.build_dir
if os.path.isabs(build_dir):
return build_dir
else:
return os.path.join(top_dir, build_dir)
def __get_cmd_dict(self):
return {
'make' : self.__get_make(),
'configure_args' : self.get_active_conf().configure.args or '',
'configure_vars' : self.expand_env(self.get_active_conf().configure.vars),
}
def get_command(self, cmd, filename, topdir):
return expand_command(getattr(self.commands, cmd),
self.__get_cmd_dict(),
filename, topdir,
self.get_build_dir(topdir))
factory_template = """\
<?xml version="1.0" encoding="UTF-8"?>
<medit-project version="2.0" type="C" name="%(project_name)s">
<active>debug</active>
<configurations>
<configuration name="debug">
<build_dir>build/debug</build_dir>
<configure>
<args>--enable-debug</args>
<vars>
<var name="CFLAGS">-g</var>
<var name="CXXFLAGS">-g</var>
</vars>
</configure>
</configuration>
<configuration name="optimized">
<build_dir>build/optimized</build_dir>
<configure>
<vars>
<var name="CFLAGS">-g -O2</var>
<var name="CXXFLAGS">-g -O2</var>
</vars>
</configure>
</configuration>
</configurations>
</medit-project>
"""
_sample_file = """
<medit-project name="moo" type="C" version="2.0">
<commands>
<compile>
<cmd>$(make) $(base).o</cmd>
<working_dir>$(builddir)</working_dir>
</compile>
</commands>
<make>
<flags>-j 3</flags>
</make>
<run>
<exe>medit</exe>
<args>--g-fatal-warnings</args>
</run>
<configurations>
<configuration name="debug">
<configure>
<args>--enable-debug=full --enable-all-gcc-warnings</args>
<vars>
<var name="CFLAGS">-O0 -g3 -pg</var>
</vars>
</configure>
<build_dir>build/debug</build_dir>
</configuration>
<configuration name="optimized">
<configure>
<args>--enable-all-gcc-warnings</args>
<vars>
<var name="CFLAGS">-g -O2</var>
</vars>
</configure>
<build_dir>build/optimized</build_dir>
</configuration>
</configurations>
<active>debug</active>
</medit-project>
"""
if __name__ == '__main__':
from mprj.config import File
s1 = _sample_file
c = CConfig(File(s1))
s2 = str(c.get_xml())
print s2
c = CConfig(File(s2))
s3 = str(c.get_xml())
assert s2 == s3

View File

@ -0,0 +1,240 @@
#
# cproj/optdialog.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import gobject
import gtk
import os.path
import moo
from moo.utils import _
import mprj.optdialog
import mprj.simple
from mprj.config.view import *
from cproj.config import *
class ConfigsPage(mprj.optdialog.ConfigPage):
__label__ = _('Configurations')
__types__ = {'config_build_dir' : Entry,
'config_args' : Entry,
'config_vars' : DictView}
def load_config(self, config):
if config is not None:
self.xml.w_config_build_dir.set_setting(config['build_dir'])
self.xml.w_config_args.set_setting(config.configure['args'])
self.xml.w_config_vars.set_dict(config.configure['vars'])
else:
self.xml.w_config_build_dir.set_setting(None)
self.xml.w_config_args.set_setting(None)
self.xml.w_config_vars.set_dict(None)
def combo_changed(self, *whatever):
self.do_apply()
combo = self.xml.w_configuration
iter = combo.get_active_iter()
config = None
if iter is not None:
store = combo.get_model()
config = store.get_value(iter, 1)
self.load_config(config)
def init_combo(self):
store = gtk.ListStore(str, object)
combo = self.xml.w_configuration
combo.set_model(store)
cell = gtk.CellRendererText()
combo.pack_start(cell)
combo.set_attributes(cell, text=0)
active = (0,)
configurations = self.config.configurations
for name in sorted(configurations.keys()):
c = configurations[name]
iter = store.append([c.name, c])
if c is self.config.get_active_conf():
active = store.get_path(iter)
combo.set_active_iter(store.get_iter(active))
combo.connect('changed', self.combo_changed)
def update_buttons(self):
self.xml.w_delete_configuration.set_sensitive(len(self.config.configurations) > 1)
def rename_config_cb(self, *whatever):
combo = self.xml.w_configuration
iter = combo.get_active_iter()
store = combo.get_model()
config = store.get_value(iter, 1)
name = config.name
new_name = mprj.utils.entry_dialog(parent=self,
label=_("Enter new name"),
entry_content=name,
title=_("Enter new name"))
if not new_name or new_name == name:
return
if self.config.configurations.has_key(new_name):
mprj.utils.error_dialog(parent=self, text=_("Configuration '%s' already exists") % (new_name))
return
was_active = self.config.active == name
self.config.rename_conf(name, new_name)
store.set_value(iter, 0, new_name)
if was_active:
self.config.active = new_name
def add_config_cb(self, *whatever):
name = mprj.utils.entry_dialog(parent=self,
label=_("Enter configuration name"),
title=_("Enter configuration name"))
if not name:
return
if self.config.configurations.has_key(name):
mprj.utils.error_dialog(parent=self, text=_("Configuration '%s' already exists") % (name))
return
new_conf = self.config.add_conf(name)
combo = self.xml.w_configuration
store = combo.get_model()
iter = store.append([name, new_conf])
combo.set_active_iter(iter)
def delete_config_cb(self, *whatever):
combo = self.xml.w_configuration
iter = combo.get_active_iter()
store = combo.get_model()
config = store.get_value(iter, 1)
do_delete = mprj.utils.question_dialog(parent=self,
text=_("Delete configuration %s?" % (config.name,)),
default_ok=False)
if do_delete:
self.config.delete_conf(config.name)
store.remove(iter)
combo.set_active(0)
self.update_buttons()
def do_init(self):
mprj.optdialog.ConfigPage.do_init(self)
self.init_combo()
self.combo_changed()
self.xml.w_add_configuration.connect('clicked', self.add_config_cb)
self.xml.w_rename_configuration.connect('clicked', self.rename_config_cb)
self.xml.w_delete_configuration.connect('clicked', self.delete_config_cb)
self.update_buttons()
class RunOptionsPage(mprj.optdialog.ConfigPage):
__label__ = _('Run options')
__types__ = {'vars' : DictView,
'exe' : Entry,
'args' : Entry}
def do_init(self):
mprj.optdialog.ConfigPage.do_init(self)
self.xml.w_vars.set_dict(self.config.run.vars)
self.xml.w_exe.set_setting(self.config.run['exe'])
self.xml.w_args.set_setting(self.config.run['args'])
run_from = self.config.run.run_from
if run_from == RUN_FROM_BUILD_DIR:
self.xml.w_build_dir.set_active(True)
elif run_from == RUN_FROM_EXE_DIR:
self.xml.w_exe_dir.set_active(True)
else:
self.xml.w_custom_dir.set_active(True)
self.xml.w_custom_dir_entry.set_text(run_from)
moo.utils.bind_sensitive(self.xml.w_custom_dir,
self.xml.w_custom_dir_entry)
def do_apply(self):
mprj.optdialog.ConfigPage.do_apply(self)
if self.xml.w_build_dir.get_active():
self.config.run.run_from = RUN_FROM_BUILD_DIR
elif self.xml.w_exe_dir.get_active():
self.config.run.run_from = RUN_FROM_EXE_DIR
else:
self.config.run.run_from = self.xml.w_custom_dir_entry.get_text()
class BuildCommandsPage(mprj.optdialog.ConfigPage):
__label__ = _('Build commands')
__types__ = {'commands' : GroupView}
def do_init(self):
mprj.optdialog.ConfigPage.do_init(self)
self.xml.w_commands.set_group(self.config.commands)
def do_apply(self):
mprj.optdialog.ConfigPage.do_apply(self)
class Dialog(mprj.optdialog.Dialog):
def __init__(self, project):
mprj.optdialog.Dialog.__init__(self, project)
glade_file = os.path.join(os.path.dirname(__file__), 'options.glade')
# self.append_page(mprj.simple.ConfigPage(self.config_copy))
self.append_page(ConfigsPage('page_configs', self.config_copy, glade_file))
self.append_page(RunOptionsPage('page_run', self.config_copy, glade_file))
self.append_page(BuildCommandsPage('page_commands', self.config_copy, glade_file))
def do_apply(self):
# print '--------------------------------'
# print self.config_copy.commands.compile
# print '--------------------------------'
mprj.optdialog.Dialog.do_apply(self)
self.project.apply_config()
# print '--------------------------------'
# print self.config_copy.commands.compile
# print '--------------------------------'
# print self.project.config.commands.compile
# print '--------------------------------'
gobject.type_register(ConfigsPage)
gobject.type_register(RunOptionsPage)
gobject.type_register(BuildCommandsPage)
gobject.type_register(Dialog)
if __name__ == '__main__':
import gtk
from cproj.config import CConfig, _sample_file
from mprj.config import File
from c import CProject
editor = moo.edit.create_editor_instance()
config_file = File(_sample_file, '/tmp/test-file.mprj')
config = CConfig(config_file)
project = CProject(None, config, config_file)
dialog = Dialog(project)
dialog.connect('destroy', gtk.main_quit)
dialog.run()
gtk.main()

View File

@ -0,0 +1,553 @@
<?xml version="1.0"?>
<glade-interface>
<requires-version lib="gtk+" version="2.12"/>
<widget class="GtkWindow" id="window4">
<child>
<widget class="GtkNotebook" id="notebook1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tab_pos">GTK_POS_LEFT</property>
<child>
<widget class="GtkVBox" id="page_configs">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox6">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;_Configuration:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">configuration</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="configuration">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="items"></property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="rename_configuration">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">_Rename...</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="delete_configuration">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">_Delete...</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="add_configuration">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">_New...</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkEntry" id="config_args">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="config_build_dir">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">_Arguments:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">config_args</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">_Build directory:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">config_build_dir</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment8">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="config_vars">
<property name="visible">True</property>
<property name="rules_hint">True</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Environment variables:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">config_vars</property>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="label" translatable="yes">Configurations</property>
</widget>
<packing>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="page_run">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Run from&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment6">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="build_dir">
<property name="visible">True</property>
<property name="label" translatable="yes" comments="Run program from build directory">Build directory</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="exe_dir">
<property name="visible">True</property>
<property name="label" translatable="yes" comments="Run program from its directory">Executable directory</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
<property name="group">build_dir</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="custom_dir">
<property name="visible">True</property>
<property name="label" translatable="yes" comments="Run program from custom directory">Custom:</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
<property name="group">build_dir</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="custom_dir_entry">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Program&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkEntry" id="args">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="exe">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Executable:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Arguments:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Environment variables&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="vars">
<property name="visible">True</property>
<property name="rules_hint">True</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="label" translatable="yes">Run options</property>
</widget>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="page_commands">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Build commands&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="commands">
<property name="visible">True</property>
<property name="headers_visible">False</property>
<property name="rules_hint">True</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="label" translatable="yes">Build commands</property>
</widget>
<packing>
<property name="position">2</property>
<property name="tab_fill">False</property>
<property name="type">tab</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,49 @@
#
# cproj/parser.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import re
errors = [
r'In file included from (?P<file>[^:]+):(?P<line>\d+):.*',
r'(?P<file>[^:]+):(?P<line>\d+):(\d+:)?\s*error\s*:.*',
r'(?P<file>[^:]+):(?P<line>\d+):.*',
]
warnings = [
r'(?P<file>[^:]+):(?P<line>\d+):(\d+:)?\s*warning\s*:.*',
]
errors = [re.compile(e) for e in errors]
warnings = [re.compile(e) for e in warnings]
class ErrorInfo(object):
def __init__(self, file, line, type='error'):
object.__init__(self)
self.file = file
self.line = line - 1
self.type = type
def parse_make_error(line):
for p in errors:
m = p.match(line)
if not m:
continue
return ErrorInfo(m.group('file'), int(m.group('line')))
for p in warnings:
m = p.match(line)
if not m:
continue
return ErrorInfo(m.group('file'), int(m.group('line')), 'warning')
return None

View File

@ -0,0 +1,15 @@
#
# pyproj/__init__.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#

View File

@ -0,0 +1,65 @@
#
# pyproj/config.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import os.path
import moo
from moo.utils import _
from mprj.settings import *
from mprj.simple import SimpleConfig
class RunOptions(Group):
__items__ = {
'exe' : String(name=_('Script file')),
'args' : String(name=_('Arguments')),
'vars' : Dict(str, xml_elm_name='var'),
}
__item_name__ = _('Run options')
class PyConfig(SimpleConfig):
__items__ = {
'run' : RunOptions,
}
def get_exe(self, top_dir):
ro = self.run
return ro.exe, ro.args, top_dir
factory_template = """\
<medit-project name="%(project_name)s" type="Python" version="2.0">
</medit-project>
"""
_sample_file = """
<medit-project name="foo" type="Python" version="2.0">
<run>
<exe>foo.py</exe>
<args>--blah</args>
</run>
</medit-project>
"""
if __name__ == '__main__':
from mprj.config import File
s1 = _sample_file
c = PyConfig(File(s1))
s2 = str(c.get_xml())
print s2
c = PyConfig(File(s2))
s3 = str(c.get_xml())
assert s2 == s3

View File

@ -0,0 +1,77 @@
#
# pyproj/optdialog.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../../..'))
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import gobject
import os.path
import moo
from moo.utils import _
import mprj.optdialog
from mprj.config.view import *
from pyproj.config import *
class RunOptionsPage(mprj.optdialog.ConfigPage):
__label__ = _('Run options')
__types__ = {'vars' : DictView,
'exe' : Entry,
'args' : Entry}
def do_init(self):
self.xml.w_vars.set_dict(self.config.run.vars)
self.xml.w_exe.set_setting(self.config.run['exe'])
self.xml.w_args.set_setting(self.config.run['args'])
class Dialog(moo.utils.PrefsDialog):
def __init__(self, project, title=_('Project Options')):
moo.utils.PrefsDialog.__init__(self, title)
self.project = project
self.config_copy = project.config.copy()
# self.append_page(mprj.simple.ConfigPage(self.config_copy))
glade_file = os.path.join(os.path.dirname(__file__), 'options.glade')
self.append_page(RunOptionsPage('page_run', self.config_copy, glade_file))
def do_apply(self):
moo.utils.PrefsDialog.do_apply(self)
self.project.config.copy_from(self.config_copy)
self.project.save_config()
# print '============================='
# print self.project.config.dump_xml()
# print '============================='
gobject.type_register(RunOptionsPage)
gobject.type_register(Dialog)
if __name__ == '__main__':
import gtk
from pyproj.config import PyConfig, _sample_file
from mprj.config import File
from python import PyProject
editor = moo.edit.create_editor_instance()
file = File(_sample_file, '/tmp/fake/file')
config = PyConfig(file)
project = PyProject(None, config, file)
dialog = Dialog(project)
dialog.connect('destroy', gtk.main_quit)
dialog.run()
gtk.main()

View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!-- Generated with glade3
Version: 3.0.0
Date: Sat Jan 13 00:09:27 2007
User: muntyan
Host: munt10
-->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="page_run">
<property name="visible">True</property>
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0.000000</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="bottom_padding">3</property>
<property name="left_padding">3</property>
<property name="right_padding">3</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkEntry" id="args">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="exe">
<property name="visible">True</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">1.000000</property>
<property name="label" translatable="yes">Main file:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">1.000000</property>
<property name="label" translatable="yes">Arguments:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Program:</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0.000000</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="bottom_padding">3</property>
<property name="left_padding">3</property>
<property name="right_padding">3</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTreeView" id="vars">
<property name="visible">True</property>
<property name="rules_hint">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="label" translatable="yes">Environment variables:</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,151 @@
#
# python.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
if __name__ == '__main__':
import sys
import os.path
dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(dir, '../..'))
sys.path.insert(0, os.path.join(dir, '..'))
import gtk
import os.path
import gobject
import moo
from moo.utils import _, N_
import medit
import mprj.utils
from mprj.simple import SimpleProject
from mprj.utils import print_error
import pyproj.config
from pyproj.config import PyConfig
from pyproj.optdialog import Dialog as OptionsDialog
_STOCK_EXECUTE = moo.utils.STOCK_EXECUTE
_STOCK_PROJECT_OPTIONS = moo.utils.STOCK_PROJECT_OPTIONS
_OUTPUT_PANE_ID = "PythonOutput"
_CMD_EXECUTE = 'execute'
_CMD_EXECUTE_FILE = 'execute_file'
class PyProject(SimpleProject):
__config__ = PyConfig
__factory_name__ = "Python"
__factory_template__ = pyproj.config.factory_template
class DoCmd(object):
def __init__(self, proj, *args):
object.__init__(self)
self.proj = proj
self.args = args
def __call__(self, window):
return self.proj.do_command(window, *self.args)
def init_ui(self):
SimpleProject.init_ui(self)
self.panes.extend([_OUTPUT_PANE_ID])
commands = [
["Execute", _("Execute Program"), _STOCK_EXECUTE, "F9", _CMD_EXECUTE],
["ExecuteFile", _("Execute File"), _STOCK_EXECUTE, "<shift>F9", _CMD_EXECUTE_FILE],
]
for c in commands:
self.add_action("PyProject" + c[0],
display_name=c[1], label=c[1],
stock_id=c[2], default_accel=c[3],
callback=PyProject.DoCmd(self, c[4]))
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
xml.insert_markup_after(self.merge_id, "Editor/Menubar",
"Project", """
<item name="Build" _label="%s">
<item action="PyProjectExecute"/>
<item action="PyProjectExecuteFile"/>
</item>
""" % (N_("_Build"),))
xml.insert_markup(self.merge_id, "Editor/Toolbar/BuildToolbar",
0, """
<item action="PyProjectExecute"/>
<separator/>
""")
def get_file_path(self, file):
if os.path.exists(file):
return file
bd = self.config.get_build_dir(self.topdir)
f = os.path.join(bd, file)
if os.path.exists(f):
return f
f = os.path.join(self.topdir, file)
if os.path.exists(f):
return f
return None
def save_all(self, window):
docs = window.list_docs()
for d in docs:
if d.get_filename() and d.get_status() & moo.edit.EDIT_MODIFIED:
d.save()
def do_command(self, window, cmd):
try:
self.before_command(window, cmd) and \
self.exec_command(window, cmd) and \
self.after_command(window, cmd)
except Exception, e:
mprj.utils.oops(window, e)
def before_command(self, window, cmd):
self.save_all(window)
return True
def after_command(self, window, cmd):
return True
def __cmd_execute(self, window):
filename, args, working_dir = self.config.get_exe(self.topdir)
r = medit.runpython.Runner(window, pane_id=_OUTPUT_PANE_ID)
r.run(filename, args, working_dir)
return True
def __cmd_execute_file(self, window):
r = medit.runpython.Runner(window, pane_id=_OUTPUT_PANE_ID)
r.run()
return True
def exec_command(self, window, cmd):
if cmd == _CMD_EXECUTE:
return self.__cmd_execute(window)
elif cmd == _CMD_EXECUTE_FILE:
return self.__cmd_execute_file(window)
else:
mprj.utils.implement_me(window, "Command " + cmd)
return False
def create_options_dialog(self):
return OptionsDialog(self)
__project__ = PyProject
__project_type__ = "Python"
__project_version__ = "2.0"

View File

@ -0,0 +1,67 @@
#
# pytest.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import moo
import gobject
PLUGIN_ID = "TestPythonPlugin"
class Action(moo.edit.Action):
def __init__(self):
moo.edit.Action.__init__(self)
self.set_property("label", "AnAction")
#print "__init__"
def do_check_state(self):
#print "check_state"
return True
def do_activate(self):
#print "activate: doc is", self.doc
pass
class Plugin(moo.edit.Plugin):
def do_init(self):
#print "do_init"
return True
def do_deinit(self):
#print "do_deinit"
pass
def do_attach_win(self, window):
#print "do_attach_win"
pass
def do_detach_win(self, window):
#print "do_detach_win"
pass
def do_attach_doc(self, doc, window):
#print "do_attach_doc"
pass
def do_detach_doc(self, doc, window):
#print "do_detach_doc"
pass
if moo.edit.module_check_version(2, 0):
gobject.type_register(Action)
gobject.type_register(Plugin)
info = moo.edit.PluginInfo("RealPythonPlugin", "Real Python Plugin",
description="Plugin", author="Uknown",
version="3.1415926")
moo.edit.plugin_register(Plugin, info)

View File

@ -0,0 +1,11 @@
[module]
type=Python
file=python.py
version=@MOO_MODULE_MAJOR_VERSION@.@MOO_MODULE_MINOR_VERSION@
[plugin]
id=Python
_name=Python
_description=Python support
author=Yevgen Muntyan <muntyan@tamu.edu>
version=@MOO_VERSION_UNQUOTED@

View File

@ -0,0 +1,120 @@
#
# python.py
#
# Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@tamu.edu>
#
# This file is part of medit. medit is free software; you can
# redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License,
# or (at your option) any later version.
#
# You should have received a copy of the GNU Lesser General Public
# License along with medit. If not, see <http://www.gnu.org/licenses/>.
#
import gtk
import gobject
import pango
import os
import moo
from moo.utils import _
import medit.runpython
MASTER_FILE = 'PYTHON_MASTER_FILE'
try:
import pyconsole
have_pyconsole = True
except ImportError:
have_pyconsole = False
PLUGIN_ID = "Python"
class Plugin(moo.edit.Plugin):
def do_init(self):
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
if xml is None:
# standalone python module, not in medit
return False
self.ui_merge_id = xml.new_merge_id()
if have_pyconsole:
moo.utils.window_class_add_action(moo.edit.EditWindow, "PythonConsole",
display_name=_("Python Console"),
label=_("Python Console"),
callback=self.show_console)
xml.add_item(self.ui_merge_id, "ToolsMenu",
"PythonConsole", "PythonConsole", -1)
""" Run file """
moo.utils.window_class_add_action(moo.edit.EditWindow, "RunFile",
display_name=_("Run File"),
label=_("Run File"),
stock_id=moo.utils.STOCK_EXECUTE,
default_accel="<shift>F9",
callback=self.run_file)
moo.edit.window_set_action_filter("RunFile", moo.edit.ACTION_CHECK_SENSITIVE, "langs:python")
xml.add_item(self.ui_merge_id, "ToolsMenu",
"RunFile", "RunFile", -1)
return True
def do_deinit(self):
editor = moo.edit.editor_instance()
xml = editor.get_ui_xml()
xml.remove_ui(self.ui_merge_id)
moo.utils.window_class_remove_action(moo.edit.EditWindow, "PythonConsole")
moo.utils.window_class_remove_action(moo.edit.EditWindow, "RunFile")
moo.utils.window_class_remove_action(moo.edit.EditWindow, "ReloadPythonPlugins")
def show_console(self, window):
window = gtk.Window()
swin = gtk.ScrolledWindow()
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
window.add(swin)
dic = {}
dic['editor'] = moo.edit.editor_instance()
dic['window'] = moo.edit.editor_instance().get_active_window()
dic['doc'] = moo.edit.editor_instance().get_active_doc()
console_type = pyconsole.ConsoleType(moo.edit.TextView)
console = console_type(use_rlcompleter=False, start_script=
"import moo\nimport gtk\n", locals=dic)
console.set_property("highlight-current-line", False)
editor = moo.edit.editor_instance()
console.set_lang_by_id("python-console")
console.modify_font(pango.FontDescription("Monospace"))
swin.add(console)
window.set_default_size(400,300)
window.set_title("pythony")
window.show_all()
def run_file(self, window):
filename = os.environ.get(MASTER_FILE)
if filename is None:
doc = window.get_active_doc()
if not doc:
return
if not doc.get_filename() or doc.get_status() & moo.edit.EDIT_MODIFIED:
if not doc.save():
return
filename = doc.get_filename()
r = medit.runpython.Runner(window)
r.run(filename)
def do_detach_win(self, window):
window.remove_pane(PLUGIN_ID)
gobject.type_register(Plugin)
__plugin__ = Plugin

Some files were not shown because too many files have changed in this diff Show More