diff --git a/CMakeLists.txt b/CMakeLists.txt
index 965e76c746cf6254b6aba9f08f6c3f7bde9b6d73..b1a28eb40ac2cf3fc4cca83c88d71c6683511527 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -43,6 +43,7 @@ option(ENABLE_PARSER "Build the GEO file parser" ON)
 option(ENABLE_PETSC "Enable PETSc linear algebra solvers" ON)
 option(ENABLE_POST "Build the post-processing module" ON)
 option(ENABLE_QT "Build QT GUI" OFF)
+option(ENABLE_READLINE "Enable Readline in Lua prompt" ON)
 option(ENABLE_SLEPC "Enable SLEPc eigensolvers" ON)
 option(ENABLE_SOLVER "Enable solver components" ON)
 option(ENABLE_TAUCS "Enable Taucs linear algebra solver" ON)
@@ -667,6 +668,21 @@ if(ENABLE_OSMESA)
   endif(OSMESA_LIB)
 endif(ENABLE_OSMESA)
 
+if(HAVE_LUA)
+  if(ENABLE_READLINE)
+    find_library(READLINE_LIB readline PATH_SUFFIXES lib)
+    if(READLINE_LIB)
+      find_path(READLINE_INC "readline.h" PATH_SUFFIXES src readline include)
+      if(READLINE_INC)
+        set(HAVE_READLINE TRUE)
+        list(APPEND CONFIG_OPTIONS "Readline")
+        list(APPEND EXTERNAL_LIBRARIES ${READLINE_LIB})
+        list(APPEND EXTERNAL_INCLUDES ${READLINE_INC})
+      endif(READLINE_INC)
+    endif(READLINE_LIB)
+  endif(ENABLE_READLINE)
+endif(HAVE_LUA)
+
 include(CheckFunctionExists)
 check_function_exists(vsnprintf HAVE_VSNPRINTF)
 if(NOT HAVE_VSNPRINTF)
@@ -1003,4 +1019,5 @@ message("Run 'ccmake ${CMAKE_SOURCE_DIR}' to fine-tune the configuration.")
 message("")
 
 mark_as_advanced(BISON FLEX GMP_LIB GMSH_EXTRA_VERSION HDF5_LIB MAKEINFO 
-                 MED_LIB OCC_INC SZ_LIB TAUCS_LIB LUA_LIB TEXI2PDF)
+                 MED_LIB OCC_INC SZ_LIB TAUCS_LIB LUA_LIB TEXI2PDF
+                 READLINE_LIB)
diff --git a/Common/Bindings.h b/Common/Bindings.h
index c0d2f0368ce4d2a8c4934ed958c6e1756d029bce..0b254c188180ee00381285c693b1f4fb0b03d464 100644
--- a/Common/Bindings.h
+++ b/Common/Bindings.h
@@ -6,9 +6,11 @@
 #include "GmshConfig.h"
 
 class methodBinding{
+  std::string _description;
   public:
   void setArgNames(std::string arg1, ...){}
-  void setDescription(std::string description){}
+  void setDescription(std::string description){_description=description;}
+  inline const std::string getDescription() const {return _description;}
 };
 
 #if defined(HAVE_LUA)
@@ -17,4 +19,5 @@ class methodBinding{
 #include "DummyBindings.h"
 #endif
 
+
 #endif
diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 4838a6826f2faaf1f50d5594ac8d52b889e29a90..5268a3148653124b18f7145947c62dd075efe57b 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -96,6 +96,9 @@ void PrintUsage(const char *name)
   Msg::Direct("  -                     Parse input files, then exit");
 #if defined(HAVE_FLTK)
   Msg::Direct("  -a, -g, -m, -s, -p    Start in automatic, geometry, mesh, solver or post-processing mode");
+#endif
+#if defined(HAVE_LUA)
+  Msg::Direct("  -lua                  Start an interactive lua session");
 #endif
   Msg::Direct("  -pid                  Print process id on stdout");
   Msg::Direct("  -listen               Always listen to incoming connection requests");
@@ -603,6 +606,12 @@ void GetOptions(int argc, char *argv[])
           Msg::Fatal("Missing argument");
       }
 #endif
+#if defined (HAVE_LUA)
+      else if(!strcmp(argv[i] + 1, "lua")) {
+        i++;
+        CTX::instance()->batch = -4;
+      }
+#endif
 #if defined(__APPLE__)
       else if(!strncmp(argv[i] + 1, "psn", 3)) {
         // The Mac Finder launches programs with a special command
diff --git a/Common/Context.h b/Common/Context.h
index 7571f953e7611f81bc61f4d9c9e9985366583078..720f5b3ccfe4994e050cabe7375a27d3df304a4a 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -92,11 +92,11 @@ class CTX {
   int fileChooserPosition[2];
   // use the system menu bar on Mac OS X?
   int systemMenuBar;
-  // batch mode (-3: server daemon, -2: check coherence, -1: write
+  // batch mode (-4: lua session, -3: server daemon, -2: check coherence, -1: write
   // geo, 0: full gfx, 1: 1D mesh, 2: 2D mesh, 3: 3D mesh, 4: adapt
   // mesh, 5: refine mesh)
   int batch; 
-  // batch operations to appy after meshing (1: partition mesh)
+  // batch operations to apply after meshing (1: partition mesh)
   int batchAfterMesh;
   // initial menu (0: automatic, 1: geom, 2: mesh, 3: solver, 4: post)
   int initialContext;
diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 33b7760072985671db783397b8dac0c24a23a966..cbcb48aa248e40e56061e086b7361d30c50a0c82 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -28,6 +28,10 @@
 #include "PluginManager.h"
 #endif
 
+#if defined(HAVE_LUA)
+#include "LuaBindings.h"
+#endif
+
 int GmshInitialize(int argc, char **argv)
 {
   // we need at least one model during option parsing
@@ -141,6 +145,12 @@ int GmshBatch()
   }
 #endif
 
+#if defined(HAVE_LUA)
+  if(CTX::instance()->batch == -4){
+    binding::instance()->interactiveSession();
+  }
+  else 
+#endif 
   if(CTX::instance()->batch == -3){
     GmshRemote();
   }
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index 245960ab20f22ce30901e2f7b1f02284db09591f..97c42ba0b6ac0d49c95c38a9528055e6e146bc0b 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -38,6 +38,7 @@
 #cmakedefine HAVE_PETSC
 #cmakedefine HAVE_POST
 #cmakedefine HAVE_QT
+#cmakedefine HAVE_READLINE
 #cmakedefine HAVE_SLEPC
 #cmakedefine HAVE_SOLVER
 #cmakedefine HAVE_TAUCS
diff --git a/Common/LuaBindings.cpp b/Common/LuaBindings.cpp
index b88a153fc3bc5ca46ab661c16b863e392c3eb902..5b8c729213d5efc7a2310f26850b7e4fed24ce2a 100644
--- a/Common/LuaBindings.cpp
+++ b/Common/LuaBindings.cpp
@@ -1,6 +1,7 @@
 #include "GmshConfig.h"
 #ifdef HAVE_LUA
 #include <iostream>
+#include <string>
 #include "Gmsh.h"
 #include "Bindings.h"
 #include "dgSystemOfEquations.h"
@@ -16,16 +17,130 @@ extern "C" {
   #include "lualib.h"
   #include "lauxlib.h"
 }
-void report_errors(lua_State *L, int status)
+
+#ifdef HAVE_READLINE
+#include "readline.h"
+#include "history.h"
+#endif
+
+static void report_errors(lua_State *L, int status)
 {
   if ( status!=0 ) {
     std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
     lua_pop(L, 1); // remove error message
   }
 }
-int read_lua(const char *filename)
+
+const char *colorRed = "\033[1;31m";
+const char *colorGreen = "\033[1;32m";
+const char *colorBlue = "\033[1;34m";
+const char *colorDefault = "\033[0m";
+const char *colorBold = "\033[1m";
+
+static void list_methods(classBinding *cb){
+  if(cb->methods.size())
+    std::cout<<colorBold<<"Methods from "<<cb->getClassName()<<colorDefault<<"\n";
+  for(std::map<std::string,luaMethodBinding *>::iterator it = cb->methods.begin(); it!=cb->methods.end(); it++){
+    std::cout<<colorBlue<<"  "<<it->first<<colorDefault<<" : ";
+    const std::string description=it->second->getDescription();
+    std::cout<<(description.empty()?"no help available":description) <<"\n";
+  }
+  if(cb->getParent())
+    list_methods(cb->getParent());
+}
+
+static int lua_help (lua_State *L){
+  int argc = lua_gettop(L);
+  binding *b = binding::instance();
+  if (argc==0){
+    std::cout<<"this is the gmsh help\n";
+    for(std::map<std::string,classBinding *>::iterator it = b->classes.begin(); it!=b->classes.end(); it++){
+      if(it->second->getParent())
+        continue;
+      std::cout<<colorBlue<<"  "<<it->first<<colorDefault<<" : ";
+      const std::string description=it->second->getDescription();
+      std::cout<<(description.empty()?"no help available":description) <<"\n";
+    }
+  }else{
+    const char *className = luaL_checkstring(L,1);
+    if(b->classes.find(className)==b->classes.end()){
+      std::cout<<"Class "<<colorBold<<className<<colorDefault<<" does not exist.\n";
+      return 0;
+    }
+    classBinding *cb = b->classes[className];
+    std::cout<<"\n"<<colorRed<<className<<colorDefault<<"\n";
+    const std::string description=cb->getDescription();
+    std::cout<<(description.empty()?"no help available":description) <<"\n";
+    std::cout<<"\n";
+    list_methods(cb);
+    std::cout<<"\n";
+    if(cb->children.size()){
+      std::cout<<colorBold<<"Children of "<<cb->getClassName()<<colorDefault<<"\n";
+      for(std::set<classBinding *>::iterator it = cb->children.begin(); it!=cb->children.end(); it++){
+        std::cout<<"  "<<colorGreen<<(*it)->getClassName()<<colorDefault<<" : ";
+        const std::string description=(*it)->getDescription();
+        std::cout<<(description.empty()?"no help available":description) <<"\n";
+      }
+      std::cout<<"\n";
+    }
+  }
+  return 0;
+}
+#ifdef HAVE_READLINE
+static int lua_save (lua_State *L){
+  const char *filename = luaL_checkstring(L,1);
+  write_history(filename);
+  return 0;
+}
+static int lua_clear (lua_State *L){
+  clear_history();
+  return 0;
+}
+#endif
+
+int binding::readFile(const char *filename)
 {
-  lua_State *L = lua_open();
+  int s = luaL_loadfile(L, filename);
+  if ( s==0 ) {
+    Msg::Info("lua executes %s\n",filename);
+    s = lua_pcall(L, 0, LUA_MULTRET, 0);
+  }
+  report_errors(L, s);
+  lua_close(L);
+  return (s==0);
+}
+
+void binding::interactiveSession(){
+  Msg::Info("Starting interactive lua session, press Ctrl-D to exit"); 
+  #ifdef HAVE_READLINE
+  using_history();
+  while (const char *line=readline("lua> ")){
+    char *expansion;
+    int r=history_expand((char*)line,&expansion);
+    if(r)
+      std::cout<<expansion<<"\n";
+    if(r==0 || r==1){
+      add_history(expansion);
+      report_errors(L, luaL_dostring(L, expansion));
+    }
+    free(expansion);
+  }
+  clear_history();
+  #else
+  while(std::string line,
+        std::cout<<"lua> ",
+        getline(std::cin,line) ){
+    report_errors(L, luaL_dostring(L, line.c_str()));
+  }
+  #endif
+}
+
+binding::binding(){
+  if(_instance){
+    Msg::Error("Only one instance of lua bindings is allowed");
+  }
+  _instance=this;
+  L = lua_open();
   luaopen_base(L);
   luaopen_table(L);
   luaopen_os(L);
@@ -33,32 +148,26 @@ int read_lua(const char *filename)
   luaopen_string(L);
   luaopen_math(L);
   luaopen_debug(L);
-  binding b;
-  b.L=L;
+
+  lua_register(L,"help",lua_help);
+  #ifdef HAVE_READLINE
+  lua_register(L,"saveHistory",lua_save);
+  lua_register(L,"clearHistory",lua_clear);
+  #endif
 
   // Register Lua bindings
-  GModel::registerBindings(&b);
-  dgSystemOfEquations::registerBindings(&b);
-  dgBoundaryCondition::registerBindings(&b);
-  dgConservationLaw::registerBindings(&b);
-  dgConservationLawShallowWater2dRegisterBindings(&b);
-  dgConservationLawWaveEquationRegisterBindings(&b);
-  dgConservationLawAdvectionRegisterBindings(&b);
-  dgPerfectGasLaw2dRegisterBindings(&b);
-  fullMatrix<double>::registerBindings(&b);
-  function::registerBindings(&b);
-  functionLua::registerBindings(&b);
+  GModel::registerBindings(this);
+  dgSystemOfEquations::registerBindings(this);
+  dgBoundaryCondition::registerBindings(this);
+  dgConservationLaw::registerBindings(this);
+  dgConservationLawShallowWater2dRegisterBindings(this);
+  dgConservationLawWaveEquationRegisterBindings(this);
+  dgConservationLawAdvectionRegisterBindings(this);
+  dgPerfectGasLaw2dRegisterBindings(this);
+  fullMatrix<double>::registerBindings(this);
+  function::registerBindings(this);
+  functionLua::registerBindings(this);
   function::registerDefaultFunctions();
-
-  int s = luaL_loadfile(L, filename);
-
-  if ( s==0 ) {
-    printf("lua executes %s\n",filename);
-    s = lua_pcall(L, 0, LUA_MULTRET, 0);
-  }
-  report_errors(L, s);
-
-  lua_close(L);
-  return (s==0);
 }
+binding *binding::_instance=NULL;
 #endif
diff --git a/Common/LuaBindings.h b/Common/LuaBindings.h
index 96756a0b5445c3bc3372f442359158bc7ebd74ad..290387e0bc576083568332d65d602741b8ef282c 100644
--- a/Common/LuaBindings.h
+++ b/Common/LuaBindings.h
@@ -2,14 +2,28 @@
 #define _LUA_BINDINGS_H_
 #include "Bindings.h"
 #ifdef HAVE_LUA
-int read_lua(const char *filename);
+#include "BindingsDocTemplates.h"
 
 extern "C" {
 #include "lua.h"
 #include "lauxlib.h"
 }
 #include <vector>
+#include <set>
 
+class classBinding;
+class binding {
+  static binding *_instance;
+  public:
+  inline static binding *instance(){return _instance ? _instance : new binding();}
+  lua_State *L;
+  int readFile(const char *filename);
+  void interactiveSession();
+  binding();
+  std::map<std::string,classBinding *> classes;
+  template<class t>
+  classBinding *addClass(std::string className);
+};
 
 /*** store a unique static class name for each binded class ***/
 template <typename type>
@@ -302,12 +316,15 @@ template <typename cb>
 class methodBindingT:public luaMethodBinding {
   public:
   cb _f;
-  methodBindingT(const std::string luaname,cb f):luaMethodBinding(luaname){
+  methodBindingT(const std::string luaname,cb f):luaMethodBinding(luaname) {
     _f=f;
   }
   int call (lua_State *L) {
     return luaCall(L,_f);
   }
+  void getArgNames(std::string &returnTypeName, std::vector<std::string> &argTypeName) {
+    getArgNames(_f,returnTypeName,argTypeName);
+  }
 };
 
 template <typename tObj, typename t0=void, typename t1=void , typename t2=void, typename t3=void>
@@ -357,10 +374,9 @@ class constructorBindingT<tObj,t0,t1,t2,void>:public luaMethodBinding {
   }
 };
 
-
 class classBinding {
   std::string _className;
-  lua_State *_L;
+  binding *_b;
   static int callMethod(lua_State *L) {
     return  static_cast<luaMethodBinding*>(lua_touserdata(L, lua_upvalueindex(1)))->call(L); 
   }
@@ -381,19 +397,25 @@ class classBinding {
     return 1;
   }
   void setConstructorLuaMethod(luaMethodBinding *constructor){
-    lua_getglobal(_L,_className.c_str());
-    int methods = lua_gettop(_L);
-    lua_getmetatable(_L,methods);
-    int mt = lua_gettop(_L);
-    lua_pushlightuserdata(_L,(void*)constructor);
-    lua_pushcclosure(_L, callMethod, 1);
-    lua_setfield(_L, mt,"__call");
-    lua_pop(_L,2);
-  }
+    lua_State *L = _b->L;
+    lua_getglobal(L,_className.c_str());
+    int methods = lua_gettop(L);
+    lua_getmetatable(L,methods);
+    int mt = lua_gettop(L);
+    lua_pushlightuserdata(L,(void*)constructor);
+    lua_pushcclosure(L, callMethod, 1);
+    lua_setfield(L, mt,"__call");
+    lua_pop(L,2);
+  }
+  //for the doc
+  std::string _description;
+  classBinding *_parent;
 public:
+  std::set<classBinding *> children;
   // get userdata from Lua stack and return pointer to T object
-  classBinding(lua_State *L, std::string name){
-    _L=L;
+  classBinding(binding *b, std::string name){
+    _b=b;
+    lua_State *L = _b->L;
     _className=name;
 
     // there are 3 tables involved :
@@ -423,30 +445,42 @@ public:
   } 
   template<typename parentType>
   void setParentClass(){
+    if(_parent)
+      Msg::Error("Multiple inheritance not implemented in lua bindings for class %s",_className.c_str());
     std::string parentClassName=className<parentType>::get();
-    lua_getglobal(_L,_className.c_str());
-    lua_getmetatable(_L,-1);
-    int mt=lua_gettop(_L);
-    lua_getglobal(_L,parentClassName.c_str());
-    lua_setfield(_L,mt,"__index");// mt.__index = global[_parentClassName] // this is the inheritance bit
-    lua_pop(_L,2);
+    _parent = _b->classes[parentClassName];
+    _parent->children.insert(this);
+    lua_getglobal(_b->L,_className.c_str());
+    lua_getmetatable(_b->L,-1);
+    int mt=lua_gettop(_b->L);
+    lua_getglobal(_b->L,parentClassName.c_str());
+    lua_setfield(_b->L,mt,"__index");// mt.__index = global[_parentClassName] // this is the inheritance bit
+    lua_pop(_b->L,2);
+  }
+
+  void setDescription(std::string description){
+    _description = description;
   }
-  void setDescription(std::string description){};
+  inline const std::string getDescription()const {return _description;};
+  inline classBinding *getParent()const {return _parent;};
+  std::map<std::string, luaMethodBinding *> methods;
 
   template <typename cb>
   methodBinding *addMethod(std::string n, cb f){
     luaMethodBinding *mb = new methodBindingT<cb>(n,f);
+    methods[n]=mb;
+    lua_State *L=_b->L;
 
-    lua_getglobal(_L,_className.c_str());
-    int methods=lua_gettop(_L);
+    lua_getglobal(L,_className.c_str());
+    int methods=lua_gettop(L);
     /*int (*lc)(lua_State *,cb)=(int(*)(lua_State*,cb))luaCall;
-    lua_pushlightuserdata(_L, (void*)lc);
-    lua_pushlightuserdata(_L, (void*)f);
-    lua_pushcclosure(_L, callMethod2, 2);*/
-    lua_pushlightuserdata(_L, (void*)mb);
-    lua_pushcclosure(_L, callMethod, 1);
-    lua_setfield(_L,methods, n.c_str()); //className.name = callMethod(mb)
-    lua_pop(_L,1);
+    lua_pushlightuserdata(L, (void*)lc);
+    lua_pushlightuserdata(L, (void*)f);
+    lua_pushcclosure(L, callMethod2, 2);*/
+    lua_pushlightuserdata(L, (void*)mb);
+    lua_pushcclosure(L, callMethod, 1);
+    lua_setfield(L,methods, n.c_str()); //className.name = callMethod(mb)
+    lua_pop(L,1);
     return mb; 
   }
   template <typename tObj, typename t0, typename t1, typename t2, typename t3 >
@@ -479,19 +513,15 @@ public:
     setConstructorLuaMethod(constructorLua);
     return constructorLua;
   }
+  inline const std::string getClassName()const {return _className;}
 };
 
-class binding {
-  public:
-  lua_State *L;
-  template<class t>
-  classBinding *addClass(std::string className);
-};
 
 template<typename t>
 classBinding *binding::addClass(std::string name){
   className<t>::set(name);
-  classBinding *cb=new classBinding(L,name);
+  classBinding *cb=new classBinding(this,name);
+  classes[name]=cb;
   return cb;
 }
 #endif
diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index 4f7b19aa25a50f10fcef345ac0b8aea4985ea87c..fdb7b72b35e8533da1cdc27271578e1e366aeeff 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -332,7 +332,7 @@ int MergeFile(std::string fileName, bool warnIfMissing)
 #endif
 #if defined(HAVE_LUA)
   else if(ext == ".lua" || ext == ".LUA") {
-    status = read_lua(fileName.c_str());
+    status = binding::instance()->readFile(fileName.c_str());
   }
 #endif
   else {
diff --git a/doc/gmsh.1 b/doc/gmsh.1
index 0c644ace787b5882175d3e9033e2d62abe6b17c9..f4dd4cc2b2bf94f63da099b694ffbcd0403eb234 100644
--- a/doc/gmsh.1
+++ b/doc/gmsh.1
@@ -120,6 +120,9 @@ parse input files, then exit.
 .B \-a, \-g, \-m, \-s, \-p
 start in automatic, geometry, mesh, solver or post-processing mode.
 .TP 4
+.B \-lua
+start an interactive lua session.
+.TP 4
 .B \-pid
 print pid on stdout.
 .TP 4
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 1efa6f92191e8670189f7d19a386a851b9478653..31503f03f605763c57cb2a3964f1284e785bb565 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -915,6 +915,8 @@ Specify display
 Parse input files, then exit
 @item -a, -g, -m, -s, -p
 Start in automatic, geometry, mesh, solver or post-processing mode
+@item -lua
+Start an interactive lua session
 @item -pid
 Print pid on stdout
 @item -listen