Saturday, July 2, 2011

run IronPython through a native application like VIM

Hi,

With Python I have macros in VIM that let me execute individual Python
lines or Python blocks of code.
Since I'm currently working with .NET I wanted to have that with
IronPython, too.
Googling showed that it's very easy to embed IronPython in .NET
applications. But VIM is a native application.
Since I just wanted to execute IronPython code from within VIM without
exposing VIM types to IronPython a solution was at hand.

I created a mixed mode DLL (ironpythonToC.dll) in C++/CLI and exposed
two C functions,
one to execute code (ExecuteInIronPython) and one to retrieve a value
(FromIronPythonAsString) (see the code below).

These functions can be executed from all native applications and well,
from C Python, too.
Since I have Python enabled in VIM I used the latter. It allows me to
get the text from the vim buffer.
Via Python ctype it is possible to load the DLL and execute the text.
Here are the Python ctype definitions of the functions (I use Python 3.1
on this Windows machine):

############ Python ctype definitions of function from ironpythonToC.dll
##################
from ctypes import LibraryLoader,WinDLL,CFUNCTYPE,c_bool,c_wchar_p
#ironpythonToC.dll needs to be in PATH, e.g. copy it to C:\Windows
dll=LibraryLoader(WinDLL).LoadLibrary("ironpythonToC.dll");
#
pExecuteInIronPython = CFUNCTYPE(c_bool, c_wchar_p)
paramflags = (1, "code"),
ExecuteInIronPython = pExecuteInIronPython(("ExecuteInIronPython", dll),
paramflags)
#
pFromIronPythonAsString = CFUNCTYPE(c_wchar_p, c_wchar_p)
paramflags = (1, "name"),
FromIronPythonAsString =
pFromIronPythonAsString(("FromIronPythonAsString", dll), paramflags)
#
#example:
#ExecuteInIronPython("t=[2,3]+[4,5]")
#FromIronPythonAsString("t")
############ Python ctype definitions of function from ironpythonToC.dll
##################

Source code of ironpythonToC.dll
====================
Here is the ironpythonToC header:

////////////////////////////////////// ironpythonToC.h
//////////////////////////////
#pragma once
extern "C" __declspec(dllexport) bool ExecuteInIronPython(wchar_t *code);
extern "C" __declspec(dllexport) const wchar_t
*FromIronPythonAsString(wchar_t *name);
////////////////////////////////////// end ironpythonToC.h
//////////////////////////////

And here is the implementation:

////////////////////////////////////// ironpythonToC.cpp
//////////////////////////////
#include "stdafx.h"
#include < vcclr.h >
#include <wchar.h>
#include "ironpythonToC.h"
#include <string>


using namespace System;
using namespace IronPython::Hosting;
using namespace Microsoft::Scripting;
using namespace Microsoft::Scripting::Hosting;


public ref class IronPythonWrapper
{
ScriptEngine ^engine;
ScriptScope ^scope;

IronPythonWrapper()
{
engine = Python::CreateEngine();
scope = engine->CreateScope();
}

public:
static IronPythonWrapper ^Instance = gcnew IronPythonWrapper();

bool Execute(System::String ^code)
{
bool result = true;
try
{
ScriptSource ^source =
engine->CreateScriptSourceFromString(code, SourceCodeKind::Statements);
source->Execute(scope);
}
catch (System::Exception ^)
{
result = false;
}
return result;
}
System::String ^GetVariable(System::String ^name)
{
System::String ^res = "";
try
{
System::String ^resAsString="res0xhshtela821h";
Execute(resAsString+"=str("+name+")");
Object ^o = scope->GetVariable(resAsString);
res = o->ToString();
}
catch (System::Exception ^)
{
res = "";
}
return res;
}
};

bool ExecuteInIronPython(wchar_t *code)
{
System::String ^codeDotNet = gcnew System::String(code);
return IronPythonWrapper::Instance->Execute(codeDotNet);
}

const wchar_t *FromIronPythonAsString(wchar_t *name)
{
static wchar_t *result = NULL;
System::String ^n = gcnew System::String(name);
System::String ^str = IronPythonWrapper::Instance->GetVariable(n);

int len = str->Length;
pin_ptr<const wchar_t> wch = PtrToStringChars(str);

if (result != NULL)
free(result);
result = (wchar_t *)malloc(sizeof(wchar_t)*(len+1));

wcscpy_s(result,len+1,wch);
return result;
}

////////////////////////////////////// end ironpythonToC.cpp
//////////////////////////////

I also attach the ironpythonToC.dll itself. Move it to C:\Windows. You
need IronPython itself installed of course.

Regards,
Roland

--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

No comments:

Post a Comment