Resurrected pygtk bindings
parent
b0be51ae76
commit
8952ec83a6
|
@ -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`)
|
||||
|
||||
|
|
|
@ -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
|
||||
])
|
|
@ -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 --------------------------------------
|
|
@ -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
|
||||
])
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ G_BEGIN_DECLS
|
|||
|
||||
#define MOO_EDIT_IS_UNTITLED(edit) (!(edit)->priv->file)
|
||||
|
||||
struct MooEditPrivate {
|
||||
struct _MooEditPrivate {
|
||||
MooEditor *editor;
|
||||
|
||||
gulong modified_changed_handler_id;
|
||||
|
|
|
@ -38,17 +38,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
|
||||
{
|
||||
MooTextView parent;
|
||||
MooEditConfig *config;
|
||||
MooEditPrivate *priv;
|
||||
};
|
||||
|
||||
struct MooEditClass
|
||||
struct _MooEditClass
|
||||
{
|
||||
MooTextViewClass parent_class;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef struct VarArray VarArray;
|
|||
typedef struct Value Value;
|
||||
|
||||
|
||||
struct MooEditConfigPrivate {
|
||||
struct _MooEditConfigPrivate {
|
||||
MOO_IP_ARRAY_ELMS (Value, values);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ typedef enum {
|
|||
EMBEDDED = 1 << 5
|
||||
} MooEditorOptions;
|
||||
|
||||
struct MooEditorPrivate {
|
||||
struct _MooEditorPrivate {
|
||||
MooEditArray *windowless;
|
||||
MooEditWindowArray *windows;
|
||||
MooUiXml *doc_ui_xml;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct MooFileEnc MooFileEnc;
|
||||
typedef struct _MooFileEnc MooFileEnc;
|
||||
|
||||
typedef struct MooEdit MooEdit;
|
||||
typedef struct MooEditWindow MooEditWindow;
|
||||
typedef struct MooEditor MooEditor;
|
||||
typedef struct _MooEdit MooEdit;
|
||||
typedef struct _MooEditWindow MooEditWindow;
|
||||
typedef struct _MooEditor MooEditor;
|
||||
|
||||
MOO_DECLARE_OBJECT_ARRAY (MooEditArray, moo_edit_array, MooEdit)
|
||||
MOO_DECLARE_OBJECT_ARRAY (MooEditWindowArray, moo_edit_window_array, MooEditWindow)
|
||||
|
|
|
@ -75,7 +75,7 @@ typedef struct {
|
|||
static GHashTable *action_checks; /* char* -> ActionCheck* */
|
||||
static GSList *windows;
|
||||
|
||||
struct MooEditWindowPrivate {
|
||||
struct _MooEditWindowPrivate {
|
||||
MooEditor *editor;
|
||||
|
||||
guint statusbar_idle;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -89,9 +89,6 @@ MooEditArray *moo_edit_window_get_docs (MooEditWindow *window)
|
|||
GSList *moo_edit_window_list_docs (MooEditWindow *window);
|
||||
int moo_edit_window_num_docs (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,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct MooFileEnc {
|
||||
struct _MooFileEnc {
|
||||
GFile *file;
|
||||
char *encoding;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ struct DndInfo {
|
|||
};
|
||||
|
||||
|
||||
struct MooIconViewPrivate {
|
||||
struct _MooIconViewPrivate {
|
||||
GtkTreeModel *model;
|
||||
|
||||
CellInfo pixbuf;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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).
|
|
@ -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
|
@ -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
|
@ -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')
|
|
@ -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)
|
|
@ -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> :</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> :</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)
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
|
@ -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()
|
|
@ -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`
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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()
|
|
@ -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)
|
|
@ -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/>.
|
||||
#
|
|
@ -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)
|
|
@ -0,0 +1,4 @@
|
|||
[module]
|
||||
type=Python
|
||||
file=pycmd.py
|
||||
version=@MOO_MODULE_MAJOR_VERSION@.@MOO_MODULE_MINOR_VERSION@
|
|
@ -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")
|
|
@ -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
|
|
@ -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>
|
|
@ -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"
|
|
@ -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 *
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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__()
|
|
@ -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 []
|
|
@ -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
|
|
@ -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')
|
|
@ -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()
|
|
@ -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())
|
|
@ -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"><b>Project _type</b></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"><b>Properties</b></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>
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
|
@ -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"><b>General</b></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"><b>Variables</b></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>
|
|
@ -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
|
|
@ -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/>.
|
||||
#
|
||||
|
|
@ -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>
|
|
@ -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')
|
|
@ -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
|
|
@ -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)
|
|
@ -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"
|
|
@ -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/>.
|
||||
#
|
||||
|
|
@ -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
|
|
@ -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()
|
|
@ -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"><b>_Configuration:</b></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"><b>Run from</b></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"><b>Program</b></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"><b>Environment variables</b></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"><b>Build commands</b></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>
|
|
@ -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
|
|
@ -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/>.
|
||||
#
|
||||
|
|
@ -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
|
|
@ -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()
|
|
@ -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>
|
|
@ -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"
|
|
@ -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)
|
|
@ -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@
|
|
@ -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
|
|
@ -0,0 +1,14 @@
|
|||
[module]
|
||||
type=Python
|
||||
file=simple.py
|
||||
# this version string must match whatever is used in current version
|
||||
# it is not a plugin version
|
||||
version=1.0
|
||||
|
||||
[plugin]
|
||||
id=APlugin
|
||||
_name=A Plugin
|
||||
_description=A plugin
|
||||
author=Some Guy
|
||||
# this is a plugin version, can be anything
|
||||
version=3.1415926
|
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
import moo
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
class Plugin(moo.edit.Plugin):
|
||||
# this method is called when plugin is loaded, once per session
|
||||
# (or after user checks Enabled in Preferences dialog)
|
||||
def do_init(self):
|
||||
editor = moo.edit.editor_instance()
|
||||
xml = editor.get_ui_xml()
|
||||
self.ui_merge_id = xml.new_merge_id()
|
||||
# Create a new action associated with editor windows
|
||||
moo.utils.window_class_add_action(moo.edit.EditWindow,
|
||||
"AnAction", # unique action id
|
||||
display_name="Do Something", # what user sees in Configure Shortcuts dialog
|
||||
label="Do Something", # menu item label
|
||||
stock_id=gtk.STOCK_APPLY, # stock icon
|
||||
callback=self.do_stuff # the action callback
|
||||
)
|
||||
# and add it into the xml, so it's actually persent in menu
|
||||
xml.add_item(self.ui_merge_id, "Editor/Menubar/Tools", action="AnAction")
|
||||
|
||||
return True
|
||||
|
||||
# this method is called when plugin is unloaded (on program exit or when plugin is disabled)
|
||||
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, "AnAction")
|
||||
|
||||
def do_stuff(self, window):
|
||||
doc = window.get_active_doc()
|
||||
if doc is not None:
|
||||
buf = doc.get_buffer()
|
||||
buf.insert_at_cursor("Hi there")
|
||||
|
||||
|
||||
# Register the plugin type with pygtk
|
||||
gobject.type_register(Plugin)
|
||||
# __plugin__ variable is picked up by plugin loader, it must be the plugin type
|
||||
__plugin__ = Plugin
|
|
@ -0,0 +1,11 @@
|
|||
[module]
|
||||
type=Python
|
||||
file=terminal.py
|
||||
version=@MOO_MODULE_MAJOR_VERSION@.@MOO_MODULE_MINOR_VERSION@
|
||||
|
||||
[plugin]
|
||||
id=Terminal
|
||||
_name=Terminal
|
||||
_description=Terminal plugin
|
||||
author=Yevgen Muntyan <muntyan@tamu.edu>
|
||||
version=@MOO_VERSION_UNQUOTED@
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue