New Upstream Snapshot - themole

Ready changes

Summary

Merged new upstream version: 0.3+git20131102.1.daacccf (was: 0.3).

Resulting package

Built on 2023-01-25T02:46 (took 4m26s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots themole

Lintian Result

Diff

diff --git a/commands.py b/commands.py
index d521126..5694b5e 100644
--- a/commands.py
+++ b/commands.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from sys import exit
 from urllib.parse import urlencode, parse_qs
@@ -313,11 +313,14 @@ class QueryCommand(Command):
             index_limit = params.index('limit') if 'limit' in params else -1
             index_where = params.index('where') if 'where' in params else -1
             index_offset = params.index('offset') if 'offset' in params else -1
-            min_end = min(index_limit if index_limit != -1 else 0x7fffff, index_offset if index_offset != -1 else 0x7fffff)
+            index_outfile = params.index('outfile') if 'outfile' in params else -1
+            min_end = min(index_limit if index_limit != -1 else 0x7fffff, index_outfile if index_outfile != -1 else 0x7fffff. index_offset if index_offset != -1 else 0x7fffff)
             if min_end == 0x7fffff:
                 min_end = -1
             where_end = min_end if min_end != -1 and min_end > index_where else len(params) + 1
+            outfile_end = min_end if min_end != -1 and min_end > index_outfile else len(params) + 1
             condition = ' '.join(params[index_where + 1:where_end]) if index_where != -1 else '1=1'
+            outfile = ''.join(params[index_outfile+1:outfile_end]) if index_outfile != -1 else ''
             if index_limit == len(params) - 1:
                 raise CommandException('Limit argument requires row numbers.')
             if index_offset == len(params) - 1:
@@ -340,13 +343,24 @@ class QueryCommand(Command):
         except themole.QueryError as ex:
             output_manager.error('Query error: {0}'.format(ex)).line_break()
             return
-        res_out = output_manager.results_output(columns)
-        for i in result:
-            res_out.put(i)
-        res_out.end_sequence()
+        if len(outfile) == 0:
+            res_out = output_manager.results_output(columns)
+            for i in result:
+                res_out.put(i)
+            res_out.end_sequence()
+        else:
+            output_manager.line_break()
+            try:
+                fd = open(outfile, 'a+')
+                for i in result:
+                    fd.write(', '.join(i) + '\n')
+                fd.close()
+                output_manager.info('Saved results to ' + outfile).line_break()
+            except IOError as ex:
+                output_manager.error(str(ex))
 
     def usage(self, cmd_name):
-        return cmd_name + ' <SCHEMA> <TABLE> <COLUMNS> [where <CONDITION>] [limit <NUM_ROWS>] [offset <OFFSET>]'
+        return cmd_name + ' <SCHEMA> <TABLE> <COLUMNS> [where <CONDITION>] [limit <NUM_ROWS>] [outfile <PATH>][offset <OFFSET>]'
 
     def parameters(self, mole, current_params):
         if len(current_params) == 0:
@@ -360,7 +374,7 @@ class QueryCommand(Command):
                 return []
             return tables
         elif len(current_params) == 3 :
-            return ['where', 'limit', 'offset']
+            return ['where', 'limit', 'offset', 'outfile']
         else:
             columns = mole.poll_columns(current_params[0], current_params[1])
             return columns if columns else []
diff --git a/completion.py b/completion.py
index 10c967b..c01e9dd 100644
--- a/completion.py
+++ b/completion.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 try:
     import readline
@@ -100,7 +100,7 @@ class CompletionManager:
         while match:
             output += self.nice_split(line[start_index:match.start()])
             start_index += match.end()
-            output.append(match.groups()[0][1:-1].strip())
+            output.append(match.groups()[0][1:-1])
             match = self.parse_regex.search(line[start_index:])
         if start_index < len(line):
             output += self.nice_split(line[start_index:])
diff --git a/connection/request.py b/connection/request.py
index f01fb78..43c3b87 100644
--- a/connection/request.py
+++ b/connection/request.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from urllib.parse import urlparse, urlencode
 
diff --git a/connection/requester.py b/connection/requester.py
index 52614b0..10696af 100644
--- a/connection/requester.py
+++ b/connection/requester.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import urllib.parse
 import time
@@ -101,11 +101,11 @@ class Requester(object):
 
     def request(self, query):
         """Make the request applying the filters and return the response.
-        
+
         @param query: String containing the query to inject in the
         vulnerable param.
         @return: String containing the response in html format.
-        
+
         """
 
         query = self.__query_filters.apply_filters(query)
@@ -136,6 +136,15 @@ class Requester(object):
 
         response.content = self.decode(response.content)
 
+        if len(query) > 0:
+            new_response = ''
+            while query.lower() in response.content.lower():
+                index = response.content.lower().find(query.lower())
+                new_response += response.content[:index]
+                response.content = response.content[index+len(query):]
+            new_response += response.content
+            response.content = new_response
+
         self.__response_filters.apply_filters(response)
 
         return response.content
@@ -194,11 +203,11 @@ class Requester(object):
     @property
     def get_parameters(self):
         return self.__get_parameters
-        
+
     @property
     def encoding(self):
         return self.__encoding
-    
+
     @encoding.setter
     def encoding(self, new_encoding):
         self.__encoding = new_encoding
diff --git a/connection/requestsender.py b/connection/requestsender.py
index 6c76efd..c0afa3a 100644
--- a/connection/requestsender.py
+++ b/connection/requestsender.py
@@ -16,12 +16,13 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import http.client
 import socket
+import zlib
 from urllib.parse import urlencode, urlparse
 
 from moleexceptions import ConnectionException
@@ -53,7 +54,7 @@ class BaseRequestSender():
 
         for _ in range(self.max_retries):
             try:
-                data = self.fetch_data(request, connection)
+                (data, headers) = self.fetch_data(request, connection)
                 break
             except (socket.error,
                     socket.timeout,
@@ -68,6 +69,8 @@ class BaseRequestSender():
         if data is None:
             raise ConnectionException(str(exception))
 
+        if 'Content-Encoding' in headers and headers['Content-Encoding'] == 'gzip':
+            data = decompressed_data=zlib.decompress(data, 16+zlib.MAX_WBITS)
         return Response(data)
 
 class HttpRequestSender(BaseRequestSender):
@@ -86,7 +89,7 @@ class HttpRequestSender(BaseRequestSender):
             connection.request('GET', parsed.path, None, request.headers)
             resp = connection.getresponse()
             resp_headers = dict(resp.getheaders())
-        return resp.read()
+        return (resp.read(), resp_headers)
 
     def __str__(self):
         return 'httpsender'
@@ -102,7 +105,7 @@ class HttpHeadRequestSender(BaseRequestSender):
         output = ''
         for header in headers:
             output += '<div>{0} {1}</div>\n'.format(header, headers[header])
-        return '<html><body>{0}</body></html>'.format(output).encode()
+        return ('<html><body>{0}</body></html>'.format(output).encode(), headers)
 
     def __str__(self):
         return 'headsender'
diff --git a/connection/response.py b/connection/response.py
index 8f5c688..c37b84e 100644
--- a/connection/response.py
+++ b/connection/response.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 class Response():
     def __init__(self, content):
diff --git a/datadumper.py b/datadumper.py
index 9cc7bb2..612455a 100644
--- a/datadumper.py
+++ b/datadumper.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from moleexceptions import QueryError, ConnectionException
 
diff --git a/dbdump.py b/dbdump.py
index 7dc225c..b56fbac 100644
--- a/dbdump.py
+++ b/dbdump.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 # 
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 class DatabaseDump():
     def __init__(self):
diff --git a/dbmsmoles/__init__.py b/dbmsmoles/__init__.py
index f6a61f7..a2be468 100644
--- a/dbmsmoles/__init__.py
+++ b/dbmsmoles/__init__.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from dbmsmoles.dbmsmole import DbmsMole, FingerBase
 
diff --git a/dbmsmoles/dbmsmole.py b/dbmsmoles/dbmsmole.py
index c47f59a..421fdeb 100644
--- a/dbmsmoles/dbmsmole.py
+++ b/dbmsmoles/dbmsmole.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import re
 
diff --git a/dbmsmoles/mysql.py b/dbmsmoles/mysql.py
index 6da5716..2fc4772 100644
--- a/dbmsmoles/mysql.py
+++ b/dbmsmoles/mysql.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from . import DbmsMole, FingerBase
 
diff --git a/dbmsmoles/oracle.py b/dbmsmoles/oracle.py
index d5155af..3be1f9a 100644
--- a/dbmsmoles/oracle.py
+++ b/dbmsmoles/oracle.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from . import DbmsMole, FingerBase
 
diff --git a/dbmsmoles/postgres.py b/dbmsmoles/postgres.py
index f7ee08f..2745052 100644
--- a/dbmsmoles/postgres.py
+++ b/dbmsmoles/postgres.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from . import DbmsMole, FingerBase
 
@@ -105,7 +105,7 @@ class PostgresMole(DbmsMole):
 
     @classmethod
     def dbms_check_blind_query(cls):
-        return ' and {op_par}0 < (select length(getpgusername()))'
+        return ' and 0 < (select length(getpgusername()))'
 
     @classmethod
     def field_finger(cls, finger):
@@ -180,7 +180,7 @@ class PostgresMole(DbmsMole):
         if len(fields) == 1 and fields[0] == 'distinct(schemaname)':
             query += " distinct on(schemaname) "
             fields = ['schemaname']
-        query_list[injectable_field] = ("cast(cast(" + PostgresMole.integer_out_delimiter + 
+        query_list[injectable_field] = ("cast(cast(" + PostgresMole.integer_out_delimiter +
                                         " as varchar(10))||length(" + self._concat_fields(fields) +
                                             ")||cast(" + PostgresMole.integer_out_delimiter + " as varchar(10)) as bigint)"
                                         )
@@ -201,9 +201,9 @@ class PostgresMole(DbmsMole):
         if len(fields) == 1 and fields[0] == 'distinct(schemaname)':
             query += " distinct on(schemaname) "
             fields = ['schemaname']
-        query_list[injectable_field] = ("cast(cast(" + PostgresMole.integer_out_delimiter + 
+        query_list[injectable_field] = ("cast(cast(" + PostgresMole.integer_out_delimiter +
                                         " as varchar(10))||ascii(substring(" + self._concat_fields(fields) +
-                                        ", " + str(index)+",1))||cast(" + PostgresMole.integer_out_delimiter + 
+                                        ", " + str(index)+",1))||cast(" + PostgresMole.integer_out_delimiter +
                                         " as varchar(10)) as bigint)"
                                         )
         query += ','.join(query_list)
diff --git a/dbmsmoles/sqlserver.py b/dbmsmoles/sqlserver.py
index 8d13507..1f17b45 100644
--- a/dbmsmoles/sqlserver.py
+++ b/dbmsmoles/sqlserver.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from . import DbmsMole, FingerBase
 
@@ -110,7 +110,7 @@ class SQLServerMole(DbmsMole):
 
     @classmethod
     def dbms_check_blind_query(cls):
-        return ' and {op_par}0 < (select len(user_name()))'
+        return ' and 0 < (select len(user_name()))'
 
     @classmethod
     def dbms_name(cls):
diff --git a/debian/changelog b/debian/changelog
index d9ba482..7e7e021 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+themole (0.3+git20131102.1.daacccf-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 25 Jan 2023 02:43:27 -0000
+
 themole (0.3-3.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff --git a/domanalyser.py b/domanalyser.py
index 0d2d4ba..16cd3a7 100644
--- a/domanalyser.py
+++ b/domanalyser.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 
 import lxml.html as lxml
diff --git a/filters.py b/filters.py
index 3b6b1eb..866daaa 100644
--- a/filters.py
+++ b/filters.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import os
 import sys
diff --git a/injectioninspector.py b/injectioninspector.py
index bf6bb19..7edfb71 100644
--- a/injectioninspector.py
+++ b/injectioninspector.py
@@ -17,9 +17,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from dbmsmoles import DbmsMole
 from moleexceptions import StoppedQueryException, ConnectionException
@@ -90,11 +90,11 @@ class InjectionInspector:
             req = mole.make_request(' order by 15000')
         except ConnectionException as ex:
             raise ColumnNumberNotFound(str(ex))
-        content_of_needle = mole.analyser.node_content(req)
+        content_of_needle = mole.analyser.node_content(req) or ''
         mole.stop_query = False
         last = 2
         try:
-            new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (last,)))
+            new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (last,))) or ''
         except ConnectionException as ex:
             raise ColumnNumberNotFound(str(ex))
         while new_needle_content != content_of_needle and not DbmsMole.is_error(new_needle_content):
@@ -103,7 +103,7 @@ class InjectionInspector:
             last *= 2
             output_manager.info('Trying {0} columns'.format(last))
             try:
-                new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (last,)))
+                new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (last,))) or ''
             except ConnectionException as ex:
                 raise ColumnNumberNotFound(str(ex))
         pri = last // 2
@@ -113,7 +113,8 @@ class InjectionInspector:
             medio = ((pri + last) // 2) + ((pri + last) & 1)
             output_manager.info('Trying {0} columns'.format(medio))
             try:
-                new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (medio,)))
+                new_needle_content = mole.analyser.node_content(mole.make_request(' order by %d ' % (medio,))) or ''
+                
             except ConnectionException as ex:
                 raise ColumnNumberNotFound(str(ex))
             if new_needle_content != content_of_needle and not DbmsMole.is_error(new_needle_content):
diff --git a/mole.py b/mole.py
index 854a7f3..406f3d4 100755
--- a/mole.py
+++ b/mole.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from sys import exit
 import getopt, sys
@@ -130,7 +130,6 @@ r"""                     _____ _           ___  ___      _
                       | | | | | |  __/ | |  | | (_) | |  __/
                       \_/ |_| |_|\___| \_|  |_/\___/|_|\___|
 
- Developed by Nasel(http://www.nasel.com.ar).
  Published under GPLv3.
  Be efficient and have fun!
 """
diff --git a/moleexceptions.py b/moleexceptions.py
index aa73d89..9118098 100644
--- a/moleexceptions.py
+++ b/moleexceptions.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 #General Exceptions
 
diff --git a/outputmanager.py b/outputmanager.py
index 27652fa..62773de 100644
--- a/outputmanager.py
+++ b/outputmanager.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import sys
 import threading
diff --git a/parameters.py b/parameters.py
index 3042bfc..cb1ddb0 100644
--- a/parameters.py
+++ b/parameters.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 class Parameter:
     def __init__(self, exec_function=None, no_args_str='Expected arguments', invalid_args_function=None):
diff --git a/pyreadline/__init__.py b/pyreadline/__init__.py
new file mode 100644
index 0000000..c15af44
--- /dev/null
+++ b/pyreadline/__init__.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+from . import unicode_helper, logger, clipboard, lineeditor, modes, console
+from .rlmain import *
+from . import rlmain
diff --git a/pyreadline/clipboard/__init__.py b/pyreadline/clipboard/__init__.py
new file mode 100644
index 0000000..7c9d857
--- /dev/null
+++ b/pyreadline/clipboard/__init__.py
@@ -0,0 +1,72 @@
+import sys
+success = True
+in_ironpython = "IronPython" in sys.version
+if in_ironpython:
+    try:
+        from .ironpython_clipboard import GetClipboardText, SetClipboardText
+    except ImportError:
+        from .no_clipboard import GetClipboardText, SetClipboardText
+
+else:
+    try:
+        from .win32_clipboard import GetClipboardText, SetClipboardText
+    except ImportError:
+        from .no_clipboard import GetClipboardText, SetClipboardText
+    
+
+def send_data(lists):
+    SetClipboardText(make_tab(lists))
+    
+
+def set_clipboard_text(toclipboard):
+    SetClipboardText(str(toclipboard))
+
+def make_tab(lists):
+    if hasattr(lists, "tolist"):
+        lists = lists.tolist()
+    ut = []
+    for rad in lists:
+        if type(rad) in [list, tuple]:
+            ut.append("\t".join(["%s"%x for x in rad]))
+        else:
+            ut.append("%s"%rad)
+    return "\n".join(ut)            
+    
+def make_list_of_list(txt):
+    def make_num(x):
+        try:
+            return int(x)
+        except ValueError:
+            try:
+                return float(x)
+            except ValueError:
+                try:
+                    return complex(x)
+                except ValueError:
+                    return x
+        return x                
+    ut = []
+    flag = False
+    for rad in [x for x in txt.split("\r\n") if x != ""]:
+        raden=[make_num(x) for x in rad.split("\t")]
+        if str in list(map(type,raden)):
+            flag = True
+        ut.append(raden)
+    return ut, flag
+
+
+def get_clipboard_text_and_convert(paste_list=False):
+    """Get txt from clipboard. if paste_list==True the convert tab separated 
+    data to list of lists. Enclose list of list in array() if all elements are 
+    numeric"""
+    txt = GetClipboardText()
+    if txt:
+        if paste_list and "\t" in txt:
+            array, flag = make_list_of_list(txt)
+            if flag:
+                txt = repr(array)
+            else:
+                txt = "array(%s)"%repr(array)
+            txt = "".join([c for c in txt if c not in " \t\r\n"])
+    return txt
+
diff --git a/pyreadline/clipboard/ironpython_clipboard.py b/pyreadline/clipboard/ironpython_clipboard.py
new file mode 100644
index 0000000..6aaab65
--- /dev/null
+++ b/pyreadline/clipboard/ironpython_clipboard.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import clr
+clr.AddReferenceByPartialName("System.Windows.Forms")
+import System.Windows.Forms.Clipboard as cb
+
+def GetClipboardText():
+    text = ""
+    if cb.ContainsText():
+        text = cb.GetText()
+
+    return text
+
+def SetClipboardText(text):
+    cb.SetText(text)    
+
+if __name__ == '__main__':
+    txt = GetClipboardText()                            # display last text clipped
+    print(txt)
+     
+     
+     
+     
\ No newline at end of file
diff --git a/pyreadline/clipboard/no_clipboard.py b/pyreadline/clipboard/no_clipboard.py
new file mode 100644
index 0000000..3b3e290
--- /dev/null
+++ b/pyreadline/clipboard/no_clipboard.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+
+mybuffer = ""
+
+def GetClipboardText():
+    return mybuffer
+
+def SetClipboardText(text):
+    global mybuffer
+    mybuffer = text
+    
diff --git a/pyreadline/clipboard/win32_clipboard.py b/pyreadline/clipboard/win32_clipboard.py
new file mode 100644
index 0000000..95f966a
--- /dev/null
+++ b/pyreadline/clipboard/win32_clipboard.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Jack Trainor.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+###################################
+#
+# Based on recipe posted to ctypes-users
+# see archive
+# http://aspn.activestate.com/ASPN/Mail/Message/ctypes-users/1771866
+#
+#
+
+###################################################################################
+#
+# The Python win32clipboard lib functions work well enough ... except that they
+# can only cut and paste items from within one application, not across
+# applications or processes.
+#
+# I've written a number of Python text filters I like to run on the contents of
+# the clipboard so I need to call the Windows clipboard API with global memory
+# for my filters to work properly.
+#
+# Here's some sample code solving this problem using ctypes.
+#
+# This is my first work with ctypes.  It's powerful stuff, but passing arguments
+# in and out of functions is tricky.  More sample code would have been helpful,
+# hence this contribution.
+#
+###################################################################################
+
+from ctypes import *
+from pyreadline.keysyms.winconstants import CF_TEXT, GHND
+from pyreadline.unicode_helper import ensure_unicode,ensure_str
+
+OpenClipboard = windll.user32.OpenClipboard
+OpenClipboard.argtypes = [c_int]
+
+EmptyClipboard = windll.user32.EmptyClipboard
+
+GetClipboardData = windll.user32.GetClipboardData
+GetClipboardData.argtypes = [c_int]
+
+GetClipboardFormatName = windll.user32.GetClipboardFormatNameA
+GetClipboardFormatName.argtypes = [c_uint,c_char_p,c_int]
+
+SetClipboardData = windll.user32.SetClipboardData
+SetClipboardData.argtypes = [c_int,c_int]
+
+EnumClipboardFormats = windll.user32.EnumClipboardFormats
+EnumClipboardFormats.argtypes = [c_int]
+
+CloseClipboard = windll.user32.CloseClipboard
+CloseClipboard.argtypes = []
+
+
+GlobalAlloc = windll.kernel32.GlobalAlloc
+GlobalLock = windll.kernel32.GlobalLock
+GlobalLock.argtypes = [c_int]
+GlobalUnlock = windll.kernel32.GlobalUnlock
+GlobalUnlock.argtypes = [c_int]
+memcpy = cdll.msvcrt.memcpy
+
+def enum():
+    OpenClipboard(0)
+    q = EnumClipboardFormats(0)
+    while q:
+        q = EnumClipboardFormats(q)
+    CloseClipboard()
+
+def getformatname(format):
+    buffer = c_buffer(" "*100)
+    bufferSize = sizeof(buffer)
+    OpenClipboard(0)
+    GetClipboardFormatName(format, buffer, bufferSize)
+    CloseClipboard()
+    return buffer.value
+
+def GetClipboardText():
+    text = ""
+    if OpenClipboard(0):
+        hClipMem = GetClipboardData(CF_TEXT)
+        if hClipMem:        
+            GlobalLock.restype = c_char_p
+            text = GlobalLock(hClipMem)
+            GlobalUnlock(hClipMem)
+        CloseClipboard()
+    return ensure_unicode(text)
+
+def SetClipboardText(text):
+    buffer = c_buffer(ensure_str(text))
+    bufferSize = sizeof(buffer)
+    hGlobalMem = GlobalAlloc(c_int(GHND), c_int(bufferSize))
+    GlobalLock.restype = c_void_p
+    lpGlobalMem = GlobalLock(c_int(hGlobalMem))
+    memcpy(lpGlobalMem, addressof(buffer), c_int(bufferSize))
+    GlobalUnlock(c_int(hGlobalMem))
+    if OpenClipboard(0):
+        EmptyClipboard()
+        SetClipboardData(c_int(CF_TEXT), c_int(hGlobalMem))
+        CloseClipboard()
+
+if __name__ == '__main__':
+    txt = GetClipboardText()                            # display last text clipped
+    print(txt)
diff --git a/pyreadline/console/__init__.py b/pyreadline/console/__init__.py
new file mode 100644
index 0000000..3407b00
--- /dev/null
+++ b/pyreadline/console/__init__.py
@@ -0,0 +1,22 @@
+import glob,sys
+
+success = False
+in_ironpython = "IronPython" in sys.version
+
+if in_ironpython:
+    try:
+        from .ironpython_console import *
+        success = True
+    except ImportError:
+        raise
+else:
+    try:
+        from .console import *
+        success = True
+    except ImportError:
+        pass
+        raise
+
+if not success:
+    raise ImportError(
+            "Could not find a console implementation for your platform")
diff --git a/pyreadline/console/ansi.py b/pyreadline/console/ansi.py
new file mode 100644
index 0000000..dcfb4a5
--- /dev/null
+++ b/pyreadline/console/ansi.py
@@ -0,0 +1,190 @@
+# -*- coding: ISO-8859-1 -*-
+import re,sys,os
+
+terminal_escape = re.compile('(\001?\033\\[[0-9;]*m\002?)')
+escape_parts = re.compile('\001?\033\\[([0-9;]*)m\002?')
+
+
+class AnsiState(object):
+    def __init__(self,bold=False,inverse=False,color="white",background="black",backgroundbold=False):
+        self.bold = bold
+        self.inverse = inverse
+        self.color = color
+        self.background = background
+        self.backgroundbold = backgroundbold
+
+    trtable = {"black":0, "red":4,      "green":2,  "yellow":6,
+               "blue":1,  "magenta":5,  "cyan":3,  "white":7}
+    revtable = dict(list(zip(list(trtable.values()),list(trtable.keys()))))
+    def get_winattr(self):
+        attr = 0
+        if self.bold:
+            attr |= 0x0008
+        if self.backgroundbold:
+            attr |= 0x0080
+        if self.inverse:
+            attr |= 0x4000
+        attr |= self.trtable[self.color]
+        attr |= (self.trtable[self.background] << 4)
+        return attr
+
+    def set_winattr(self, attr):
+        self.bold = bool(attr & 0x0008)
+        self.backgroundbold = bool(attr & 0x0080)
+        self.inverse = bool(attr & 0x4000)
+        self.color = self.revtable[attr & 0x0007]
+        self.background = self.revtable[(attr & 0x0070) >> 4]
+        
+    winattr=property(get_winattr,set_winattr)
+    def __repr__(self):
+        return 'AnsiState(bold=%s,inverse=%s,color=%9s,'    \
+               'background=%9s,backgroundbold=%s)# 0x%x'%   \
+                (self.bold, self.inverse, '"%s"'%self.color,  
+                 '"%s"'%self.background, self.backgroundbold,
+                 self.winattr)
+
+    def copy(self):
+        x = AnsiState()
+        x.bold = self.bold
+        x.inverse = self.inverse
+        x.color = self.color
+        x.background = self.background
+        x.backgroundbold = self.backgroundbold
+        return x
+
+defaultstate = AnsiState(False,False,"white")
+
+trtable = {0:"black",  1:"red",       2:"green", 3:"yellow",
+           4:"blue",   5:"magenta",   6:"cyan",  7:"white"}
+
+class AnsiWriter(object):
+    def __init__(self, default=defaultstate):
+        if isinstance(defaultstate, AnsiState):
+            self.defaultstate = default
+        else:
+            self.defaultstate=AnsiState()
+            self.defaultstate.winattr = defaultstate
+            
+            
+    def write_color(self,text, attr=None):
+        '''write text at current cursor position and interpret color escapes.
+
+        return the number of characters written.
+        '''
+        if isinstance(attr,AnsiState):
+            defaultstate = attr
+        elif attr is None:  #use attribute form initial console
+            attr = self.defaultstate.copy()
+        else:
+            defaultstate = AnsiState()
+            defaultstate.winattr = attr
+            attr = defaultstate
+        chunks = terminal_escape.split(text)
+        n = 0 # count the characters we actually write, omitting the escapes
+        res=[]
+        for chunk in chunks:
+            m = escape_parts.match(chunk)
+            if m:
+                parts = m.group(1).split(";")
+                if len(parts) == 1 and parts[0] == "0":
+                    attr = self.defaultstate.copy()
+                    continue
+                for part in parts:
+                    if part == "0": # No text attribute
+                        attr = self.defaultstate.copy()
+                        attr.bold=False
+                    elif part == "7": # switch on reverse
+                        attr.inverse=True
+                    elif part == "1": # switch on bold (i.e. intensify foreground color)
+                        attr.bold=True 
+                    elif len(part) == 2 and "30" <= part <= "37": # set foreground color
+                        attr.color = trtable[int(part) - 30]
+                    elif len(part) == 2 and "40" <= part <= "47": # set background color
+                        attr.backgroundcolor = trtable[int(part) - 40]
+                continue
+            n += len(chunk)
+            if True:
+                res.append((attr.copy(), chunk))
+        return n,res
+
+    def parse_color(self,text, attr=None):
+        n,res=self.write_color(text, attr)
+        return n, [attr.winattr for attr, text in res]
+
+def write_color(text, attr=None):
+    a = AnsiWriter(defaultstate)
+    return a.write_color(text, attr)
+
+def write_color_old( text, attr=None):
+    '''write text at current cursor position and interpret color escapes.
+
+    return the number of characters written.
+    '''
+    res = []
+    chunks = terminal_escape.split(text)
+    n = 0 # count the characters we actually write, omitting the escapes
+    if attr is None:#use attribute from initial console
+        attr = 15
+    for chunk in chunks:
+        m = escape_parts.match(chunk)
+        if m:
+            for part in m.group(1).split(";"):
+                if part == "0": # No text attribute
+                    attr = 0
+                elif part == "7": # switch on reverse
+                    attr |= 0x4000
+                if part == "1": # switch on bold (i.e. intensify foreground color)
+                    attr |= 0x08
+                elif len(part) == 2 and "30" <= part <= "37": # set foreground color
+                    part = int(part)-30
+                    # we have to mirror bits
+                    attr = (attr & ~0x07) | ((part & 0x1) << 2) | (part & 0x2) | ((part & 0x4) >> 2)
+                elif len(part) == 2 and "40" <= part <= "47": # set background color
+                    part = int(part) - 40
+                    # we have to mirror bits
+                    attr = (attr & ~0x70) | ((part & 0x1) << 6) | ((part & 0x2) << 4) | ((part & 0x4) << 2)
+                # ignore blink, underline and anything we don't understand
+            continue
+        n += len(chunk)
+        if chunk:
+            res.append(("0x%x"%attr, chunk))
+    return res
+
+
+#trtable={0:"black",1:"red",2:"green",3:"yellow",4:"blue",5:"magenta",6:"cyan",7:"white"}
+
+if __name__=="__main__x":
+    import pprint
+    pprint=pprint.pprint
+
+    s="\033[0;31mred\033[0;32mgreen\033[0;33myellow\033[0;34mblue\033[0;35mmagenta\033[0;36mcyan\033[0;37mwhite\033[0m"
+    pprint (write_color(s))    
+    pprint (write_color_old(s))
+    s="\033[1;31mred\033[1;32mgreen\033[1;33myellow\033[1;34mblue\033[1;35mmagenta\033[1;36mcyan\033[1;37mwhite\033[0m"
+    pprint (write_color(s))    
+    pprint (write_color_old(s))    
+
+    s="\033[0;7;31mred\033[0;7;32mgreen\033[0;7;33myellow\033[0;7;34mblue\033[0;7;35mmagenta\033[0;7;36mcyan\033[0;7;37mwhite\033[0m"
+    pprint (write_color(s))    
+    pprint (write_color_old(s))
+    s="\033[1;7;31mred\033[1;7;32mgreen\033[1;7;33myellow\033[1;7;34mblue\033[1;7;35mmagenta\033[1;7;36mcyan\033[1;7;37mwhite\033[0m"
+    pprint (write_color(s))    
+    pprint (write_color_old(s))    
+
+    
+if __name__=="__main__":
+    from . import console
+    import pprint
+    pprint=pprint.pprint
+    
+    c=console.Console()
+    c.write_color("dhsjdhs")
+    c.write_color("\033[0;32mIn [\033[1;32m1\033[0;32m]:")
+    print()
+    pprint (write_color("\033[0;32mIn [\033[1;32m1\033[0;32m]:"))    
+    
+if __name__=="__main__x":
+    import pprint
+    pprint=pprint.pprint
+    s="\033[0;31mred\033[0;32mgreen\033[0;33myellow\033[0;34mblue\033[0;35mmagenta\033[0;36mcyan\033[0;37mwhite\033[0m"
+    pprint (write_color(s))    
diff --git a/pyreadline/console/console.py b/pyreadline/console/console.py
new file mode 100644
index 0000000..61d0c1f
--- /dev/null
+++ b/pyreadline/console/console.py
@@ -0,0 +1,845 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+'''Cursor control and color for the Windows console.
+
+This was modeled after the C extension of the same name by Fredrik Lundh. 
+'''
+
+# primitive debug printing that won't interfere with the screen
+
+import sys,os
+import traceback
+import re
+
+import pyreadline.unicode_helper as unicode_helper
+
+from pyreadline.logger import log
+from pyreadline.unicode_helper import ensure_unicode, ensure_str
+from pyreadline.keysyms import make_KeyPress, KeyPress
+from pyreadline.console.ansi import AnsiState,AnsiWriter
+
+try:
+    import ctypes.util
+    from ctypes import *
+    from _ctypes import call_function
+    from ctypes.wintypes import *
+except ImportError:
+    raise ImportError("You need ctypes to run this code")
+
+if sys.version_info < (2, 6):
+    bytes = str
+
+def nolog(string):
+    pass
+    
+log = nolog
+
+
+# some constants we need
+STD_INPUT_HANDLE = -10
+STD_OUTPUT_HANDLE = -11
+ENABLE_WINDOW_INPUT = 0x0008
+ENABLE_MOUSE_INPUT = 0x0010
+ENABLE_PROCESSED_INPUT = 0x0001
+WHITE = 0x7
+BLACK = 0
+MENU_EVENT = 0x0008
+KEY_EVENT = 0x0001
+MOUSE_MOVED = 0x0001
+MOUSE_EVENT = 0x0002
+WINDOW_BUFFER_SIZE_EVENT = 0x0004
+FOCUS_EVENT = 0x0010
+MENU_EVENT = 0x0008
+VK_SHIFT = 0x10
+VK_CONTROL = 0x11
+VK_MENU = 0x12
+GENERIC_READ = int(0x80000000)
+GENERIC_WRITE = 0x40000000
+
+# Windows structures we'll need later
+class COORD(Structure):
+    _fields_ = [("X", c_short),
+                ("Y", c_short)]
+
+class SMALL_RECT(Structure):
+    _fields_ = [("Left", c_short),
+                ("Top", c_short),
+                ("Right", c_short),
+                ("Bottom", c_short)]
+
+class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+    _fields_ = [("dwSize", COORD),
+                ("dwCursorPosition", COORD),
+                ("wAttributes", c_short),
+                ("srWindow", SMALL_RECT),
+                ("dwMaximumWindowSize", COORD)]
+
+class CHAR_UNION(Union):
+    _fields_ = [("UnicodeChar", c_wchar),
+                ("AsciiChar", c_char)]
+
+class CHAR_INFO(Structure):
+    _fields_ = [("Char", CHAR_UNION),
+                ("Attributes", c_short)]
+
+class KEY_EVENT_RECORD(Structure):
+    _fields_ = [("bKeyDown", c_byte),
+                ("pad2", c_byte),
+                ('pad1', c_short),
+                ("wRepeatCount", c_short),
+                ("wVirtualKeyCode", c_short),
+                ("wVirtualScanCode", c_short),
+                ("uChar", CHAR_UNION),
+                ("dwControlKeyState", c_int)]
+
+class MOUSE_EVENT_RECORD(Structure):
+    _fields_ = [("dwMousePosition", COORD),
+                ("dwButtonState", c_int),
+                ("dwControlKeyState", c_int),
+                ("dwEventFlags", c_int)]
+
+class WINDOW_BUFFER_SIZE_RECORD(Structure):
+    _fields_ = [("dwSize", COORD)]
+
+class MENU_EVENT_RECORD(Structure):
+    _fields_ = [("dwCommandId", c_uint)]
+
+class FOCUS_EVENT_RECORD(Structure):
+    _fields_ = [("bSetFocus", c_byte)]
+
+class INPUT_UNION(Union):
+    _fields_ = [("KeyEvent", KEY_EVENT_RECORD),
+                ("MouseEvent", MOUSE_EVENT_RECORD),
+                ("WindowBufferSizeEvent", WINDOW_BUFFER_SIZE_RECORD),
+                ("MenuEvent", MENU_EVENT_RECORD),
+                ("FocusEvent", FOCUS_EVENT_RECORD)]
+
+class INPUT_RECORD(Structure):
+    _fields_ = [("EventType", c_short),
+                ("Event", INPUT_UNION)]
+
+class CONSOLE_CURSOR_INFO(Structure):
+    _fields_ = [("dwSize", c_int),
+                ("bVisible", c_byte)]
+
+
+# I didn't want to have to individually import these so I made a list, they are
+# added to the Console class later in this file.
+
+funcs = [
+    'AllocConsole',
+    'CreateConsoleScreenBuffer',
+    'FillConsoleOutputAttribute',
+    'FillConsoleOutputCharacterW',
+    'FreeConsole',
+    'GetConsoleCursorInfo',
+    'GetConsoleMode',
+    'GetConsoleScreenBufferInfo',
+    'GetConsoleTitleW',
+    'GetProcAddress',
+    'GetStdHandle',
+    'PeekConsoleInputW',
+    'ReadConsoleInputW',
+    'ScrollConsoleScreenBufferW',
+    'SetConsoleActiveScreenBuffer',
+    'SetConsoleCursorInfo',
+    'SetConsoleCursorPosition',
+    'SetConsoleMode',
+    'SetConsoleScreenBufferSize',
+    'SetConsoleTextAttribute',
+    'SetConsoleTitleW',
+    'SetConsoleWindowInfo',
+    'WriteConsoleW',
+    'WriteConsoleOutputCharacterW',
+    'WriteFile',
+    ]
+
+# I don't want events for these keys, they are just a bother for my application
+key_modifiers = { VK_SHIFT : 1,
+                  VK_CONTROL : 1,
+                  VK_MENU : 1, # alt key
+                  0x5b : 1, # windows key
+                 }
+
+def split_block(text, size=1000):
+    return [text[start:start + size] for start in range(0, len(text), size)]
+
+
+
+class Console(object):
+    '''Console driver for Windows.
+
+    '''
+
+    def __init__(self, newbuffer=0):
+        '''Initialize the Console object.
+
+        newbuffer=1 will allocate a new buffer so the old content will be restored
+        on exit.
+        '''
+        #Do I need the following line? It causes a console to be created whenever
+        #readline is imported into a pythonw application which seems wrong. Things
+        #seem to work without it...
+        #self.AllocConsole()
+
+        if newbuffer:
+            self.hout = self.CreateConsoleScreenBuffer(
+                             GENERIC_READ | GENERIC_WRITE,
+                             0, None, 1, None)
+            self.SetConsoleActiveScreenBuffer(self.hout)
+        else:
+            self.hout = self.GetStdHandle(STD_OUTPUT_HANDLE)
+
+        self.hin = self.GetStdHandle(STD_INPUT_HANDLE)
+        self.inmode = DWORD(0)
+        self.GetConsoleMode(self.hin, byref(self.inmode))
+        self.SetConsoleMode(self.hin, 0xf)
+        info = CONSOLE_SCREEN_BUFFER_INFO()
+        self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+        self.attr = info.wAttributes
+        self.saveattr = info.wAttributes # remember the initial colors
+        self.defaultstate = AnsiState()
+        self.defaultstate.winattr = info.wAttributes
+        self.ansiwriter = AnsiWriter(self.defaultstate)
+        
+        background = self.attr & 0xf0
+        for escape in self.escape_to_color:
+            if self.escape_to_color[escape] is not None:
+                self.escape_to_color[escape] |= background
+        log('initial attr=%x' % self.attr)
+        self.softspace = 0 # this is for using it as a file-like object
+        self.serial = 0
+
+        self.pythondll = \
+            CDLL('python%s%s' % (sys.version[0], sys.version[2]))
+        self.pythondll.PyMem_Malloc.restype = c_size_t
+        self.pythondll.PyMem_Malloc.argtypes = [c_size_t]
+        self.inputHookPtr = \
+            c_void_p.from_address(addressof(self.pythondll.PyOS_InputHook)).value
+        setattr(Console, 'PyMem_Malloc', self.pythondll.PyMem_Malloc)
+
+    def __del__(self):
+        '''Cleanup the console when finished.'''
+        # I don't think this ever gets called
+        self.SetConsoleTextAttribute(self.hout, self.saveattr)
+        self.SetConsoleMode(self.hin, self.inmode)
+        self.FreeConsole()
+
+    def _get_top_bot(self):
+        info = CONSOLE_SCREEN_BUFFER_INFO()
+        self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+        rect = info.srWindow
+        top = rect.Top 
+        bot = rect.Bottom 
+        return top,bot
+
+    def fixcoord(self, x, y):
+        '''Return a long with x and y packed inside, 
+        also handle negative x and y.'''
+        if x < 0 or y < 0:
+            info = CONSOLE_SCREEN_BUFFER_INFO()
+            self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+            if x < 0:
+                x = info.srWindow.Right - x
+                y = info.srWindow.Bottom + y
+
+        # this is a hack! ctypes won't pass structures but COORD is 
+        # just like a long, so this works.
+        return c_int(y << 16 | x)
+
+    def pos(self, x=None, y=None):
+        '''Move or query the window cursor.'''
+        if x is None:
+            info = CONSOLE_SCREEN_BUFFER_INFO()
+            self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+            return (info.dwCursorPosition.X, info.dwCursorPosition.Y)
+        else:
+            return self.SetConsoleCursorPosition(self.hout, 
+                                                 self.fixcoord(x, y))
+
+    def home(self):
+        '''Move to home.'''
+        self.pos(0, 0)
+
+# Map ANSI color escape sequences into Windows Console Attributes
+
+    terminal_escape = re.compile('(\001?\033\\[[0-9;]+m\002?)')
+    escape_parts = re.compile('\001?\033\\[([0-9;]+)m\002?')
+    escape_to_color = { '0;30': 0x0,             #black
+                        '0;31': 0x4,             #red
+                        '0;32': 0x2,             #green
+                        '0;33': 0x4+0x2,         #brown?
+                        '0;34': 0x1,             #blue
+                        '0;35': 0x1+0x4,         #purple
+                        '0;36': 0x2+0x4,         #cyan
+                        '0;37': 0x1+0x2+0x4,     #grey
+                        '1;30': 0x1+0x2+0x4,     #dark gray
+                        '1;31': 0x4+0x8,         #red
+                        '1;32': 0x2+0x8,         #light green
+                        '1;33': 0x4+0x2+0x8,     #yellow
+                        '1;34': 0x1+0x8,         #light blue
+                        '1;35': 0x1+0x4+0x8,     #light purple
+                        '1;36': 0x1+0x2+0x8,     #light cyan
+                        '1;37': 0x1+0x2+0x4+0x8, #white
+                        '0': None,
+                       }
+
+    # This pattern should match all characters that change the cursor position differently
+    # than a normal character.
+    motion_char_re = re.compile('([\n\r\t\010\007])'.encode('ascii'))
+
+    def write_scrolling(self, text, attr=None):
+        '''write text at current cursor position while watching for scrolling.
+
+        If the window scrolls because you are at the bottom of the screen
+        buffer, all positions that you are storing will be shifted by the
+        scroll amount. For example, I remember the cursor position of the
+        prompt so that I can redraw the line but if the window scrolls,
+        the remembered position is off.
+
+        This variant of write tries to keep track of the cursor position
+        so that it will know when the screen buffer is scrolled. It
+        returns the number of lines that the buffer scrolled.
+
+        '''
+        x, y = self.pos()
+        w, h = self.size()
+        scroll = 0 # the result
+        # split the string into ordinary characters and funny characters
+        chunks = self.motion_char_re.split(ensure_str(text))
+        for chunk in chunks:
+            n = self.write_color(chunk, attr)
+            if len(chunk) == 1: # the funny characters will be alone
+                if chunk[0] == '\n': # newline
+                    x = 0
+                    y += 1
+                elif chunk[0] == '\r': # carriage return
+                    x = 0
+                elif chunk[0] == '\t': # tab
+                    x = 8 * (int(x / 8) + 1)
+                    if x > w: # newline
+                        x -= w
+                        y += 1
+                elif chunk[0] == '\007': # bell
+                    pass
+                elif chunk[0] == '\010':
+                    x -= 1
+                    if x < 0:
+                        y -= 1 # backed up 1 line
+                else: # ordinary character
+                    x += 1
+                if x == w: # wrap
+                    x = 0
+                    y += 1
+                if y == h: # scroll
+                    scroll += 1
+                    y = h - 1
+            else: # chunk of ordinary characters
+                x += n
+                l = int(x / w) # lines we advanced
+                x = x % w # new x value
+                y += l
+                if y >= h: # scroll
+                    scroll += y - h + 1
+                    y = h - 1
+        return scroll
+
+    def write_color(self, text, attr=None):
+        text = ensure_unicode(text)
+        n, res= self.ansiwriter.write_color(text, attr)
+        junk = DWORD(0)
+        for attr,chunk in res:
+            log("console.attr:%s"%str(attr))
+            log("console.chunk:%s"%str(chunk))
+            self.SetConsoleTextAttribute(self.hout, attr.winattr)
+            for short_chunk in split_block(chunk):
+                self.WriteConsoleW(self.hout, short_chunk, 
+                                   len(short_chunk), byref(junk), None)
+        return n
+
+    def write_plain(self, text, attr=None):
+        '''write text at current cursor position.'''
+        text = ensure_unicode(text)
+        log('write("%s", %s)' %(text, attr))
+        if attr is None:
+            attr = self.attr
+        junk = DWORD(0)
+        self.SetConsoleTextAttribute(self.hout, attr)
+        for short_chunk in split_block(chunk):
+            self.WriteConsoleW(self.hout, ensure_unicode(short_chunk), 
+                               len(short_chunk), byref(junk), None)
+        return len(text)
+
+    #This function must be used to ensure functioning with EMACS
+    #Emacs sets the EMACS environment variable
+    if "EMACS" in os.environ:
+        def write_color(self, text, attr=None):
+            text = ensure_str(text)
+            junk = DWORD(0)
+            self.WriteFile(self.hout, text, len(text), byref(junk), None)
+            return len(text)
+        write_plain = write_color
+
+    # make this class look like a file object
+    def write(self, text):
+        text = ensure_unicode(text)
+        log('write("%s")' % text)
+        return self.write_color(text)
+
+    #write = write_scrolling
+
+    def isatty(self):
+        return True
+
+    def flush(self):
+        pass
+
+    def page(self, attr=None, fill=' '):
+        '''Fill the entire screen.'''
+        if attr is None:
+            attr = self.attr
+        if len(fill) != 1:
+            raise ValueError
+        info = CONSOLE_SCREEN_BUFFER_INFO()
+        self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+        if info.dwCursorPosition.X != 0 or info.dwCursorPosition.Y != 0:
+            self.SetConsoleCursorPosition(self.hout, self.fixcoord(0, 0))
+
+        w = info.dwSize.X
+        n = DWORD(0)
+        for y in range(info.dwSize.Y):
+            self.FillConsoleOutputAttribute(self.hout, attr, 
+                                            w, self.fixcoord(0, y), byref(n))
+            self.FillConsoleOutputCharacterW(self.hout, ord(fill[0]), 
+                                             w, self.fixcoord(0, y), byref(n))
+
+        self.attr = attr
+
+    def text(self, x, y, text, attr=None):
+        '''Write text at the given position.'''
+        if attr is None:
+            attr = self.attr
+
+        pos = self.fixcoord(x, y)
+        n = DWORD(0)
+        self.WriteConsoleOutputCharacterW(self.hout, text, 
+                                          len(text), pos, byref(n))
+        self.FillConsoleOutputAttribute(self.hout, attr, n, pos, byref(n))
+
+    def clear_to_end_of_window(self):
+        top, bot = self._get_top_bot()
+        pos = self.pos()
+        w, h = self.size()
+        self.rectangle( (pos[0], pos[1], w, pos[1] + 1))
+        if pos[1] < bot:
+            self.rectangle((0, pos[1] + 1, w, bot + 1))
+
+    def rectangle(self, rect, attr=None, fill=' '):
+        '''Fill Rectangle.'''
+        x0, y0, x1, y1 = rect
+        n = DWORD(0)
+        if attr is None:
+            attr = self.attr
+        for y in range(y0, y1):
+            pos = self.fixcoord(x0, y)
+            self.FillConsoleOutputAttribute(self.hout, attr, x1 - x0, 
+                                            pos, byref(n))
+            self.FillConsoleOutputCharacterW(self.hout, ord(fill[0]), x1 - x0,
+                                             pos, byref(n))
+
+    def scroll(self, rect, dx, dy, attr=None, fill=' '):
+        '''Scroll a rectangle.'''
+        if attr is None:
+            attr = self.attr
+        x0, y0, x1, y1 = rect
+        source = SMALL_RECT(x0, y0, x1 - 1, y1 - 1)
+        dest = self.fixcoord(x0 + dx, y0 + dy)
+        style = CHAR_INFO()
+        style.Char.AsciiChar = ensure_str(fill[0])
+        style.Attributes = attr
+
+        return self.ScrollConsoleScreenBufferW(self.hout, byref(source), 
+                                          byref(source), dest, byref(style))
+
+    def scroll_window(self, lines):
+        '''Scroll the window by the indicated number of lines.'''
+        info = CONSOLE_SCREEN_BUFFER_INFO()
+        self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+        rect = info.srWindow
+        log('sw: rtop=%d rbot=%d' % (rect.Top, rect.Bottom))
+        top = rect.Top + lines
+        bot = rect.Bottom + lines
+        h = bot - top
+        maxbot = info.dwSize.Y-1
+        if top < 0:
+            top = 0
+            bot = h
+        if bot > maxbot:
+            bot = maxbot
+            top = bot - h
+
+        nrect = SMALL_RECT()
+        nrect.Top = top
+        nrect.Bottom = bot
+        nrect.Left = rect.Left
+        nrect.Right = rect.Right
+        log('sn: top=%d bot=%d' % (top, bot))
+        r=self.SetConsoleWindowInfo(self.hout, True, byref(nrect))
+        log('r=%d' % r)
+
+    def get(self):
+        '''Get next event from queue.'''
+        inputHookFunc = c_void_p.from_address(self.inputHookPtr).value
+
+        Cevent = INPUT_RECORD()
+        count = DWORD(0)
+        while 1:
+            if inputHookFunc:
+                call_function(inputHookFunc, ())
+            status = self.ReadConsoleInputW(self.hin, 
+                                        byref(Cevent), 1, byref(count))
+            if status and count.value == 1:
+                e = event(self, Cevent)
+                return e
+
+    def getkeypress(self):
+        '''Return next key press event from the queue, ignoring others.'''
+        while 1:
+            e = self.get()
+            if e.type == 'KeyPress' and e.keycode not in key_modifiers:
+                log("console.getkeypress %s"%e)
+                if e.keyinfo.keyname == 'next':
+                    self.scroll_window(12)
+                elif e.keyinfo.keyname == 'prior':
+                    self.scroll_window(-12)
+                else:
+                    return e
+            elif ((e.type == 'KeyRelease') and 
+                  (e.keyinfo == KeyPress('S', False, True, False, 'S'))):
+                log("getKeypress:%s,%s,%s"%(e.keyinfo, e.keycode, e.type))
+                return e
+            
+                
+    def getchar(self):
+        '''Get next character from queue.'''
+
+        Cevent = INPUT_RECORD()
+        count = DWORD(0)
+        while 1:
+            status = self.ReadConsoleInputW(self.hin, 
+                                            byref(Cevent), 1, byref(count))
+            if (status and 
+                (count.value == 1) and 
+                (Cevent.EventType == 1) and
+                Cevent.Event.KeyEvent.bKeyDown):
+                sym = keysym(Cevent.Event.KeyEvent.wVirtualKeyCode)
+                if len(sym) == 0:
+                    sym = Cevent.Event.KeyEvent.uChar.AsciiChar
+                return sym
+
+    def peek(self):
+        '''Check event queue.'''
+        Cevent = INPUT_RECORD()
+        count = DWORD(0)
+        status = self.PeekConsoleInputW(self.hin, 
+                                byref(Cevent), 1, byref(count))
+        if status and count == 1:
+            return event(self, Cevent)
+
+    def title(self, txt=None):
+        '''Set/get title.'''
+        if txt:
+            self.SetConsoleTitleW(txt)
+        else:
+            buffer = create_unicode_buffer(200)
+            n = self.GetConsoleTitleW(buffer, 200)
+            if n > 0:
+                return buffer.value[:n]
+
+    def size(self, width=None, height=None):
+        '''Set/get window size.'''
+        info = CONSOLE_SCREEN_BUFFER_INFO()
+        status = self.GetConsoleScreenBufferInfo(self.hout, byref(info))
+        if not status:
+            return None
+        if width is not None and height is not None:
+            wmin = info.srWindow.Right - info.srWindow.Left + 1
+            hmin = info.srWindow.Bottom - info.srWindow.Top + 1
+            #print wmin, hmin
+            width = max(width, wmin)
+            height = max(height, hmin)
+            #print width, height
+            self.SetConsoleScreenBufferSize(self.hout, 
+                                            self.fixcoord(width, height))
+        else:
+            return (info.dwSize.X, info.dwSize.Y)
+
+    def cursor(self, visible=None, size=None):
+        '''Set cursor on or off.'''
+        info = CONSOLE_CURSOR_INFO()
+        if self.GetConsoleCursorInfo(self.hout, byref(info)):
+            if visible is not None:
+                info.bVisible = visible
+            if size is not None:
+                info.dwSize = size
+            self.SetConsoleCursorInfo(self.hout, byref(info))
+
+    def bell(self):
+        self.write('\007')
+
+    def next_serial(self):
+        '''Get next event serial number.'''
+        self.serial += 1
+        return self.serial
+
+# add the functions from the dll to the class
+for func in funcs:
+    setattr(Console, func, getattr(windll.kernel32, func))
+
+if sys.version_info[:2] < (2, 6):
+    msvcrt = cdll.msvcrt
+else:
+    msvcrt = cdll.LoadLibrary(ctypes.util.find_msvcrt())
+
+_strncpy = msvcrt.strncpy
+if sys.version [:1] == 2:  #Bad fix for crash on python3
+    _strncpy.restype = c_char_p
+    _strncpy.argtypes = [c_char_p, c_char_p, c_size_t]
+_strdup = msvcrt._strdup
+_strdup.restype = c_char_p
+_strdup.argtypes = [c_char_p]
+
+LPVOID = c_void_p
+LPCVOID = c_void_p
+FARPROC = c_void_p
+LPDWORD = POINTER(DWORD)
+
+Console.AllocConsole.restype = BOOL
+Console.AllocConsole.argtypes = [] #void
+Console.CreateConsoleScreenBuffer.restype = HANDLE
+Console.CreateConsoleScreenBuffer.argtypes = [DWORD, DWORD, c_void_p, DWORD, LPVOID] #DWORD, DWORD, SECURITY_ATTRIBUTES*, DWORD, LPVOID  
+Console.FillConsoleOutputAttribute.restype = BOOL 
+Console.FillConsoleOutputAttribute.argtypes = [HANDLE, WORD, DWORD, c_int, LPDWORD] #HANDLE, WORD, DWORD, COORD, LPDWORD
+Console.FillConsoleOutputCharacterW.restype = BOOL
+Console.FillConsoleOutputCharacterW.argtypes = [HANDLE, c_ushort, DWORD, c_int, LPDWORD] #HANDLE, TCHAR, DWORD, COORD, LPDWORD
+Console.FreeConsole.restype = BOOL
+Console.FreeConsole.argtypes = [] #void
+Console.GetConsoleCursorInfo.restype = BOOL
+Console.GetConsoleCursorInfo.argtypes = [HANDLE, c_void_p] #HANDLE, PCONSOLE_CURSOR_INFO  
+Console.GetConsoleMode.restype = BOOL
+Console.GetConsoleMode.argtypes = [HANDLE, LPDWORD] #HANDLE, LPDWORD  
+Console.GetConsoleScreenBufferInfo.restype = BOOL
+Console.GetConsoleScreenBufferInfo.argtypes = [HANDLE, c_void_p] #HANDLE, PCONSOLE_SCREEN_BUFFER_INFO 
+Console.GetConsoleTitleW.restype = DWORD
+Console.GetConsoleTitleW.argtypes = [c_wchar_p, DWORD] #LPTSTR , DWORD
+Console.GetProcAddress.restype = FARPROC
+Console.GetProcAddress.argtypes = [HMODULE, c_char_p] #HMODULE , LPCSTR 
+Console.GetStdHandle.restype = HANDLE
+Console.GetStdHandle.argtypes = [DWORD]
+Console.PeekConsoleInputW.restype = BOOL
+Console.PeekConsoleInputW.argtypes = [HANDLE, c_void_p, DWORD, LPDWORD] #HANDLE, PINPUT_RECORD, DWORD, LPDWORD
+Console.ReadConsoleInputW.restype = BOOL
+Console.ReadConsoleInputW.argtypes = [HANDLE, c_void_p, DWORD, LPDWORD] #HANDLE, PINPUT_RECORD, DWORD, LPDWORD
+Console.ScrollConsoleScreenBufferW.restype = BOOL
+Console.ScrollConsoleScreenBufferW.argtypes = [HANDLE, c_void_p, c_void_p, c_int, c_void_p] #HANDLE, SMALL_RECT*, SMALL_RECT*, COORD, LPDWORD
+Console.SetConsoleActiveScreenBuffer.restype = BOOL
+Console.SetConsoleActiveScreenBuffer.argtypes = [HANDLE] #HANDLE
+Console.SetConsoleCursorInfo.restype = BOOL
+Console.SetConsoleCursorInfo.argtypes = [HANDLE, c_void_p] #HANDLE, CONSOLE_CURSOR_INFO* 
+Console.SetConsoleCursorPosition.restype = BOOL
+Console.SetConsoleCursorPosition.argtypes = [HANDLE, c_int] #HANDLE, COORD 
+Console.SetConsoleMode.restype = BOOL
+Console.SetConsoleMode.argtypes = [HANDLE, DWORD] #HANDLE, DWORD
+Console.SetConsoleScreenBufferSize.restype = BOOL
+Console.SetConsoleScreenBufferSize.argtypes = [HANDLE, c_int] #HANDLE, COORD 
+Console.SetConsoleTextAttribute.restype = BOOL
+Console.SetConsoleTextAttribute.argtypes = [HANDLE, WORD] #HANDLE, WORD 
+Console.SetConsoleTitleW.restype = BOOL
+Console.SetConsoleTitleW.argtypes = [c_wchar_p] #LPCTSTR
+Console.SetConsoleWindowInfo.restype = BOOL
+Console.SetConsoleWindowInfo.argtypes = [HANDLE, BOOL, c_void_p] #HANDLE, BOOL, SMALL_RECT*
+Console.WriteConsoleW.restype = BOOL
+Console.WriteConsoleW.argtypes = [HANDLE, c_void_p, DWORD, LPDWORD, LPVOID] #HANDLE, VOID*, DWORD, LPDWORD, LPVOID
+Console.WriteConsoleOutputCharacterW.restype = BOOL
+Console.WriteConsoleOutputCharacterW.argtypes = [HANDLE, c_wchar_p, DWORD, c_int, LPDWORD] #HANDLE, LPCTSTR, DWORD, COORD, LPDWORD
+Console.WriteFile.restype = BOOL
+Console.WriteFile.argtypes = [HANDLE, LPCVOID, DWORD, LPDWORD, c_void_p] #HANDLE, LPCVOID , DWORD, LPDWORD , LPOVERLAPPED 
+
+
+
+from .event import Event
+
+VkKeyScan = windll.user32.VkKeyScanA
+
+
+class event(Event):
+    '''Represent events from the console.'''
+    def __init__(self, console, input):
+        '''Initialize an event from the Windows input structure.'''
+        self.type = '??'
+        self.serial = console.next_serial()
+        self.width = 0
+        self.height = 0
+        self.x = 0
+        self.y = 0
+        self.char = ''
+        self.keycode = 0
+        self.keysym = '??'
+        self.keyinfo = None # a tuple with (control, meta, shift, keycode) for dispatch
+        self.width = None
+        
+        if input.EventType == KEY_EVENT:
+            if input.Event.KeyEvent.bKeyDown:
+                self.type = "KeyPress"
+            else:
+                self.type = "KeyRelease"
+            self.char = input.Event.KeyEvent.uChar.UnicodeChar
+            self.keycode = input.Event.KeyEvent.wVirtualKeyCode
+            self.state = input.Event.KeyEvent.dwControlKeyState
+            self.keyinfo = make_KeyPress(self.char,self.state,self.keycode)
+
+        elif input.EventType == MOUSE_EVENT:
+            if input.Event.MouseEvent.dwEventFlags & MOUSE_MOVED:
+                self.type = "Motion"
+            else:
+                self.type = "Button"
+            self.x = input.Event.MouseEvent.dwMousePosition.X
+            self.y = input.Event.MouseEvent.dwMousePosition.Y
+            self.state = input.Event.MouseEvent.dwButtonState
+        elif input.EventType == WINDOW_BUFFER_SIZE_EVENT:
+            self.type = "Configure"
+            self.width = input.Event.WindowBufferSizeEvent.dwSize.X
+            self.height = input.Event.WindowBufferSizeEvent.dwSize.Y
+        elif input.EventType == FOCUS_EVENT:
+            if input.Event.FocusEvent.bSetFocus:
+                self.type = "FocusIn"
+            else:
+                self.type = "FocusOut"
+        elif input.EventType == MENU_EVENT:
+            self.type = "Menu"
+            self.state = input.Event.MenuEvent.dwCommandId
+
+
+def getconsole(buffer=1):
+        """Get a console handle.
+
+        If buffer is non-zero, a new console buffer is allocated and
+        installed.  Otherwise, this returns a handle to the current
+        console buffer"""
+
+        c = Console(buffer)
+
+        return c
+
+# The following code uses ctypes to allow a Python callable to
+# substitute for GNU readline within the Python interpreter. Calling
+# raw_input or other functions that do input, inside your callable
+# might be a bad idea, then again, it might work.
+
+# The Python callable can raise EOFError or KeyboardInterrupt and
+# these will be translated into the appropriate outputs from readline
+# so that they will then be translated back!
+
+# If the Python callable raises any other exception, a traceback will
+# be printed and readline will appear to return an empty line.
+
+# I use ctypes to create a C-callable from a Python wrapper that
+# handles the exceptions and gets the result into the right form.
+
+# the type for our C-callable wrapper
+HOOKFUNC22 = CFUNCTYPE(c_char_p, c_char_p)
+HOOKFUNC23 = CFUNCTYPE(c_char_p, c_void_p, c_void_p, c_char_p)
+
+readline_hook = None # the python hook goes here
+readline_ref = None  # reference to the c-callable to keep it alive
+
+def hook_wrapper_23(stdin, stdout, prompt):
+    '''Wrap a Python readline so it behaves like GNU readline.'''
+    try:
+        # call the Python hook
+        res = ensure_str(readline_hook(prompt))
+        # make sure it returned the right sort of thing
+        if res and not isinstance(res, bytes):
+            raise TypeError('readline must return a string.')
+    except KeyboardInterrupt:
+        # GNU readline returns 0 on keyboard interrupt
+        return 0
+    except EOFError:
+        # It returns an empty string on EOF
+        res = ''
+    except:
+        print('Readline internal error', file=sys.stderr)
+        traceback.print_exc()
+        res = '\n'
+    # we have to make a copy because the caller expects to free the result
+    n = len(res)
+    p = Console.PyMem_Malloc(n + 1)
+    _strncpy(cast(p, c_char_p), res, n + 1)
+    return p
+
+def hook_wrapper(prompt):
+    '''Wrap a Python readline so it behaves like GNU readline.'''
+    try:
+        # call the Python hook
+        res = ensure_str(readline_hook(prompt))
+        # make sure it returned the right sort of thing
+        if res and not isinstance(res, bytes):
+            raise TypeError('readline must return a string.')
+    except KeyboardInterrupt:
+        # GNU readline returns 0 on keyboard interrupt
+        return 0
+    except EOFError:
+        # It returns an empty string on EOF
+        res = ''
+    except:
+        print('Readline internal error', file=sys.stderr)
+        traceback.print_exc()
+        res = '\n'
+    # we have to make a copy because the caller expects to free the result
+    p = _strdup(res)
+    return p
+
+def install_readline(hook):
+    '''Set up things for the interpreter to call 
+    our function like GNU readline.'''
+    global readline_hook, readline_ref
+    # save the hook so the wrapper can call it
+    readline_hook = hook
+    # get the address of PyOS_ReadlineFunctionPointer so we can update it
+    PyOS_RFP = c_void_p.from_address(Console.GetProcAddress(sys.dllhandle,
+                           "PyOS_ReadlineFunctionPointer".encode('ascii')))
+    # save a reference to the generated C-callable so it doesn't go away
+    if sys.version < '2.3':
+        readline_ref = HOOKFUNC22(hook_wrapper)
+    else:
+        readline_ref = HOOKFUNC23(hook_wrapper_23)
+    # get the address of the function
+    func_start = c_void_p.from_address(addressof(readline_ref)).value
+    # write the function address into PyOS_ReadlineFunctionPointer
+    PyOS_RFP.value = func_start
+
+if __name__ == '__main__':
+    import time, sys
+
+    
+    def p(char):
+        return chr(VkKeyScan(ord(char)) & 0xff)
+
+    c = Console(0)
+    sys.stdout = c
+    sys.stderr = c
+    c.page()
+    print(p("d"), p("D"))
+    c.pos(5, 10)
+    c.write('hi there')
+    print('some printed output')
+    for i in range(10):
+        q = c.getkeypress()
+        print(q)
+    del c
diff --git a/pyreadline/console/console_attributes.py b/pyreadline/console/console_attributes.py
new file mode 100644
index 0000000..9262331
--- /dev/null
+++ b/pyreadline/console/console_attributes.py
@@ -0,0 +1,16 @@
+
+FOREGROUND_BLUE           = 0x0001
+FOREGROUND_GREEN          = 0x0002
+FOREGROUND_RED            = 0x0004
+FOREGROUND_INTENSITY      = 0x0008
+BACKGROUND_BLUE           = 0x0010
+BACKGROUND_GREEN          = 0x0020
+BACKGROUND_RED            = 0x0040
+BACKGROUND_INTENSITY      = 0x0080
+COMMON_LVB_LEADING_BYTE   = 0x0100
+COMMON_LVB_TRAILING_BYTE  = 0x0200
+COMMON_LVB_GRID_HORIZONTAL= 0x0400
+COMMON_LVB_GRID_LVERTICAL = 0x0800
+COMMON_LVB_GRID_RVERTICAL = 0x1000
+COMMON_LVB_REVERSE_VIDEO  = 0x2000
+COMMON_LVB_UNDERSCORE     = 0x4000
diff --git a/pyreadline/console/consolebase.py b/pyreadline/console/consolebase.py
new file mode 100644
index 0000000..79afd24
--- /dev/null
+++ b/pyreadline/console/consolebase.py
@@ -0,0 +1,52 @@
+class baseconsole:
+    def __init__(self):
+        pass
+        
+    def bell(self):
+        raise NotImplementedError
+
+    def pos(self, x=None, y=None):
+        '''Move or query the window cursor.'''
+        raise NotImplementedError
+
+    def size(self):
+        raise NotImplementedError
+
+    def rectangle(self, rect, attr=None, fill=' '):
+        '''Fill Rectangle.'''
+        raise NotImplementedError
+
+    def write_scrolling(self, text, attr=None):
+        '''write text at current cursor position while watching for scrolling.
+
+        If the window scrolls because you are at the bottom of the screen
+        buffer, all positions that you are storing will be shifted by the
+        scroll amount. For example, I remember the cursor position of the
+        prompt so that I can redraw the line but if the window scrolls,
+        the remembered position is off.
+
+        This variant of write tries to keep track of the cursor position
+        so that it will know when the screen buffer is scrolled. It
+        returns the number of lines that the buffer scrolled.
+
+        '''
+        raise NotImplementedError
+    
+    def getkeypress(self):
+        '''Return next key press event from the queue, ignoring others.'''
+        raise NotImplementedError
+        
+    def write(self, text):
+        raise NotImplementedError
+    
+    def page(self, attr=None, fill=' '):
+        '''Fill the entire screen.'''
+        raise NotImplementedError
+
+    def isatty(self):
+        return True
+
+    def flush(self):
+        pass
+
+    
\ No newline at end of file
diff --git a/pyreadline/console/event.py b/pyreadline/console/event.py
new file mode 100644
index 0000000..05f7232
--- /dev/null
+++ b/pyreadline/console/event.py
@@ -0,0 +1,29 @@
+class Event(object):
+    '''Represent events from the console.'''
+    def __init__(self, console, input):
+        pass
+
+    def __repr__(self):
+        '''Display an event for debugging.'''
+        if self.type in ['KeyPress', 'KeyRelease']:
+            chr = self.char
+            if ord(chr)<ord("A"):
+                chr = "?"
+            s = "%s char='%s'%d keysym='%s' keycode=%d:%x state=%x keyinfo=%s" % \
+                   (self.type, chr, ord(self.char), self.keysym, self.keycode, self.keycode,
+                     self.state, self.keyinfo)
+        elif self.type in ['Motion', 'Button']:
+            s = '%s x=%d y=%d state=%x' % (self.type, self.x, self.y, self.state)
+        elif self.type == 'Configure':
+            s = '%s w=%d h=%d' % (self.type, self.width, self.height)
+        elif self.type in ['FocusIn', 'FocusOut']:
+            s = self.type
+        elif self.type == 'Menu':
+            s = '%s state=%x' % (self.type, self.state)
+        else:
+            s = 'unknown event type'
+        return s
+
+
+#    def __str__(self):
+#        return "('%s',%s,%s,%s)"%(self.char,self.key,self.state,self.keyinfo)
\ No newline at end of file
diff --git a/pyreadline/console/ironpython_console.py b/pyreadline/console/ironpython_console.py
new file mode 100644
index 0000000..25b5d3e
--- /dev/null
+++ b/pyreadline/console/ironpython_console.py
@@ -0,0 +1,424 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+'''Cursor control and color for the .NET console.
+'''
+
+#
+# Ironpython requires a patch to work do:
+#
+# In file PythonCommandLine.cs patch line:     
+#    class PythonCommandLine
+#    {
+
+# to:
+#    public class PythonCommandLine
+#    {
+#
+#
+#
+# primitive debug printing that won't interfere with the screen
+
+import clr,sys
+clr.AddReferenceToFileAndPath(sys.executable)
+import IronPythonConsole
+
+import sys
+import re
+import os
+
+import System
+
+from .event import Event
+from pyreadline.logger import log
+
+from pyreadline.keysyms import \
+    make_keysym, make_keyinfo, make_KeyPress, make_KeyPress_from_keydescr
+from pyreadline.console.ansi import AnsiState
+color = System.ConsoleColor
+
+ansicolor={"0;30": color.Black,
+           "0;31": color.DarkRed,
+           "0;32": color.DarkGreen,
+           "0;33": color.DarkYellow,
+           "0;34": color.DarkBlue,
+           "0;35": color.DarkMagenta,
+           "0;36": color.DarkCyan,
+           "0;37": color.DarkGray,
+           "1;30": color.Gray,
+           "1;31": color.Red,
+           "1;32": color.Green,
+           "1;33": color.Yellow,
+           "1;34": color.Blue,
+           "1;35": color.Magenta,
+           "1;36": color.Cyan,
+           "1;37": color.White
+          }
+
+winattr = {"black" : 0,        "darkgray" : 0+8,
+           "darkred" : 4,      "red" : 4+8,
+           "darkgreen" : 2,    "green" : 2+8,
+           "darkyellow" : 6,   "yellow" : 6+8,
+           "darkblue" : 1,     "blue" : 1+8,
+           "darkmagenta" : 5,  "magenta" : 5+8,
+           "darkcyan" : 3,     "cyan" : 3+8,
+           "gray" : 7,         "white" : 7+8}
+
+class Console(object):
+    '''Console driver for Windows.
+
+    '''
+
+    def __init__(self, newbuffer=0):
+        '''Initialize the Console object.
+
+        newbuffer=1 will allocate a new buffer so the old content will be restored
+        on exit.
+        '''
+        self.serial = 0
+        self.attr = System.Console.ForegroundColor
+        self.saveattr = winattr[str(System.Console.ForegroundColor).lower()]
+        self.savebg = System.Console.BackgroundColor
+        log('initial attr=%s' % self.attr)
+
+    def _get(self):
+        top = System.Console.WindowTop
+        log("WindowTop:%s"%top)
+        return top
+
+    def _set(self, value):
+        top = System.Console.WindowTop
+        log("Set WindowTop:old:%s,new:%s"%(top, value))
+
+    WindowTop = property(_get, _set)
+    del _get, _set
+
+    def __del__(self):
+        '''Cleanup the console when finished.'''
+        # I don't think this ever gets called
+        pass
+
+    def pos(self, x=None, y=None):
+        '''Move or query the window cursor.'''
+        if x is not None:
+            System.Console.CursorLeft=x
+        else:
+            x = System.Console.CursorLeft
+        if y is not None:
+            System.Console.CursorTop=y
+        else:
+            y = System.Console.CursorTop
+        return x, y
+
+    def home(self):
+        '''Move to home.'''
+        self.pos(0, 0)
+
+# Map ANSI color escape sequences into Windows Console Attributes
+
+    terminal_escape = re.compile('(\001?\033\\[[0-9;]*m\002?)')
+    escape_parts = re.compile('\001?\033\\[([0-9;]*)m\002?')
+
+    # This pattern should match all characters that change the cursor position differently
+    # than a normal character.
+    motion_char_re = re.compile('([\n\r\t\010\007])')
+
+    def write_scrolling(self, text, attr=None):
+        '''write text at current cursor position while watching for scrolling.
+
+        If the window scrolls because you are at the bottom of the screen
+        buffer, all positions that you are storing will be shifted by the
+        scroll amount. For example, I remember the cursor position of the
+        prompt so that I can redraw the line but if the window scrolls,
+        the remembered position is off.
+
+        This variant of write tries to keep track of the cursor position
+        so that it will know when the screen buffer is scrolled. It
+        returns the number of lines that the buffer scrolled.
+
+        '''
+        x, y = self.pos()
+        w, h = self.size()
+        scroll = 0 # the result
+
+        # split the string into ordinary characters and funny characters
+        chunks = self.motion_char_re.split(text)
+        for chunk in chunks:
+            n = self.write_color(chunk, attr)
+            if len(chunk) == 1: # the funny characters will be alone
+                if chunk[0] == '\n': # newline
+                    x = 0
+                    y += 1
+                elif chunk[0] == '\r': # carriage return
+                    x = 0
+                elif chunk[0] == '\t': # tab
+                    x = 8 * (int(x / 8) + 1)
+                    if x > w: # newline
+                        x -= w
+                        y += 1
+                elif chunk[0] == '\007': # bell
+                    pass
+                elif chunk[0] == '\010':
+                    x -= 1
+                    if x < 0:
+                        y -= 1 # backed up 1 line
+                else: # ordinary character
+                    x += 1
+                if x == w: # wrap
+                    x = 0
+                    y += 1
+                if y == h: # scroll
+                    scroll += 1
+                    y = h - 1
+            else: # chunk of ordinary characters
+                x += n
+                l = int(x / w) # lines we advanced
+                x = x % w # new x value
+                y += l
+                if y >= h: # scroll
+                    scroll += y - h + 1
+                    y = h - 1
+        return scroll
+
+    trtable = {0 : color.Black,      4 : color.DarkRed,  2 : color.DarkGreen,
+               6 : color.DarkYellow, 1 : color.DarkBlue, 5 : color.DarkMagenta,  
+               3 : color.DarkCyan,   7 : color.Gray,     8 : color.DarkGray,   
+               4+8 : color.Red,      2+8 : color.Green,  6+8 : color.Yellow,
+               1+8 : color.Blue,     5+8 : color.Magenta,3+8 : color.Cyan,
+               7+8 : color.White}
+
+    def write_color(self, text, attr=None):
+        '''write text at current cursor position and interpret color escapes.
+
+        return the number of characters written.
+        '''
+        log('write_color("%s", %s)' % (text, attr))
+        chunks = self.terminal_escape.split(text)
+        log('chunks=%s' % repr(chunks))
+        bg = self.savebg
+        n = 0 # count the characters we actually write, omitting the escapes
+        if attr is None:#use attribute from initial console
+            attr = self.attr
+        try:
+            fg = self.trtable[(0x000f&attr)]
+            bg = self.trtable[(0x00f0&attr)>>4]
+        except TypeError:
+            fg = attr
+            
+        for chunk in chunks:
+            m = self.escape_parts.match(chunk)
+            if m:
+                log(m.group(1))
+                attr = ansicolor.get(m.group(1), self.attr)
+            n += len(chunk)
+            System.Console.ForegroundColor = fg
+            System.Console.BackgroundColor = bg
+            System.Console.Write(chunk)
+        return n
+
+    def write_plain(self, text, attr=None):
+        '''write text at current cursor position.'''
+        log('write("%s", %s)' %(text, attr))
+        if attr is None:
+            attr = self.attr
+        n = c_int(0)
+        self.SetConsoleTextAttribute(self.hout, attr)
+        self.WriteConsoleA(self.hout, text, len(text), byref(n), None)
+        return len(text)
+        
+    if "EMACS" in os.environ:
+        def write_color(self, text, attr=None):
+            junk = c_int(0)
+            self.WriteFile(self.hout, text, len(text), byref(junk), None)
+            return len(text)
+        write_plain = write_color
+
+    # make this class look like a file object
+    def write(self, text):
+        log('write("%s")' % text)
+        return self.write_color(text)
+
+    #write = write_scrolling
+
+    def isatty(self):
+        return True
+
+    def flush(self):
+        pass
+
+    def page(self, attr=None, fill=' '):
+        '''Fill the entire screen.'''
+        System.Console.Clear()
+
+    def text(self, x, y, text, attr=None):
+        '''Write text at the given position.'''
+        self.pos(x, y)
+        self.write_color(text, attr)
+
+    def clear_to_end_of_window(self):
+        oldtop = self.WindowTop
+        lastline = self.WindowTop+System.Console.WindowHeight
+        pos = self.pos()
+        w, h = self.size()
+        length = w - pos[0] + min((lastline - pos[1] - 1), 5) * w - 1
+        self.write_color(length * " ")
+        self.pos(*pos)
+        self.WindowTop = oldtop
+        
+    def rectangle(self, rect, attr=None, fill=' '):
+        '''Fill Rectangle.'''
+        oldtop = self.WindowTop
+        oldpos = self.pos()
+        #raise NotImplementedError
+        x0, y0, x1, y1 = rect
+        if attr is None:
+            attr = self.attr
+        if fill:
+            rowfill = fill[:1] * abs(x1 - x0)
+        else:
+            rowfill = ' ' * abs(x1 - x0)
+        for y in range(y0, y1):
+                System.Console.SetCursorPosition(x0, y)
+                self.write_color(rowfill, attr)
+        self.pos(*oldpos)
+
+    def scroll(self, rect, dx, dy, attr=None, fill=' '):
+        '''Scroll a rectangle.'''
+        raise NotImplementedError
+
+    def scroll_window(self, lines):
+        '''Scroll the window by the indicated number of lines.'''
+        top = self.WindowTop + lines
+        if top < 0:
+            top = 0
+        if top + System.Console.WindowHeight > System.Console.BufferHeight:
+            top = System.Console.BufferHeight
+        self.WindowTop = top
+
+    def getkeypress(self):
+        '''Return next key press event from the queue, ignoring others.'''
+        ck = System.ConsoleKey
+        while 1:
+            e = System.Console.ReadKey(True)
+            if e.Key == System.ConsoleKey.PageDown: #PageDown
+                self.scroll_window(12)
+            elif e.Key == System.ConsoleKey.PageUp:#PageUp
+                self.scroll_window(-12)
+            elif str(e.KeyChar) == "\000":#Drop deadkeys
+                log("Deadkey: %s"%e)
+                return event(self, e)
+            else:
+                return event(self, e)
+
+    def title(self, txt=None):
+        '''Set/get title.'''
+        if txt:
+            System.Console.Title = txt
+        else:
+            return System.Console.Title
+
+    def size(self, width=None, height=None):
+        '''Set/get window size.'''
+        sc = System.Console
+        if width is not None and height is not None:
+            sc.BufferWidth, sc.BufferHeight = width,height
+        else:
+            return sc.BufferWidth, sc.BufferHeight
+
+        if width is not None and height is not None:
+            sc.WindowWidth, sc.WindowHeight = width,height
+        else:
+            return sc.WindowWidth - 1, sc.WindowHeight - 1
+    
+    def cursor(self, visible=True, size=None):
+        '''Set cursor on or off.'''
+        System.Console.CursorVisible = visible
+
+    def bell(self):
+        System.Console.Beep()
+
+    def next_serial(self):
+        '''Get next event serial number.'''
+        self.serial += 1
+        return self.serial
+
+class event(Event):
+    '''Represent events from the console.'''
+    def __init__(self, console, input):
+        '''Initialize an event from the Windows input structure.'''
+        self.type = '??'
+        self.serial = console.next_serial()
+        self.width = 0
+        self.height = 0
+        self.x = 0
+        self.y = 0
+        self.char = str(input.KeyChar)
+        self.keycode = input.Key
+        self.state = input.Modifiers
+        log("%s,%s,%s"%(input.Modifiers, input.Key, input.KeyChar))
+        self.type = "KeyRelease"
+        self.keysym = make_keysym(self.keycode)
+        self.keyinfo = make_KeyPress(self.char, self.state, self.keycode)
+
+def make_event_from_keydescr(keydescr):
+    def input():
+        return 1
+    input.KeyChar = "a"
+    input.Key = System.ConsoleKey.A
+    input.Modifiers = System.ConsoleModifiers.Shift
+    input.next_serial = input
+    e = event(input,input)
+    del input.next_serial
+    keyinfo = make_KeyPress_from_keydescr(keydescr)
+    e.keyinfo = keyinfo
+    return e
+
+CTRL_C_EVENT=make_event_from_keydescr("Control-c")
+
+def install_readline(hook):
+    def hook_wrap():
+        try:
+            res = hook()
+        except KeyboardInterrupt as x:   #this exception does not seem to be caught
+            res = ""
+        except EOFError:
+            return None
+        if res[-1:] == "\n":
+            return res[:-1]
+        else:
+            return res
+    class IronPythonWrapper(IronPythonConsole.IConsole):
+        def ReadLine(self, autoIndentSize): 
+            return hook_wrap()
+        def Write(self, text, style):
+            System.Console.Write(text)
+        def WriteLine(self, text, style): 
+            System.Console.WriteLine(text)
+    IronPythonConsole.PythonCommandLine.MyConsole = IronPythonWrapper()
+
+
+
+if __name__ == '__main__':
+    import time, sys
+    c = Console(0)
+    sys.stdout = c
+    sys.stderr = c
+    c.page()
+    c.pos(5, 10)
+    c.write('hi there')
+    c.title("Testing console")
+#    c.bell()
+    print()
+    print("size", c.size())
+    print('  some printed output')
+    for i in range(10):
+        e = c.getkeypress()
+        print(e.Key, chr(e.KeyChar), ord(e.KeyChar), e.Modifiers)
+    del c
+
+    System.Console.Clear()
diff --git a/pyreadline/error.py b/pyreadline/error.py
new file mode 100644
index 0000000..be2c24e
--- /dev/null
+++ b/pyreadline/error.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+
+class ReadlineError(Exception):
+    pass
+
+class GetSetError(ReadlineError):
+    pass
diff --git a/pyreadline/get_doc.py b/pyreadline/get_doc.py
new file mode 100644
index 0000000..2c5cccb
--- /dev/null
+++ b/pyreadline/get_doc.py
@@ -0,0 +1,19 @@
+import sys,textwrap
+import collections
+
+rlmain = sys.modules["pyreadline.rlmain"]
+rl = rlmain.rl
+
+def get_doc(rl):
+    methods = [(x, getattr(rl, x)) for x in dir(rl) if isinstance(getattr(rl, x), collections.Callable)]
+    return [ (x, m.__doc__ )for x, m in methods if m.__doc__]
+    
+    
+def get_rest(rl):
+    q = get_doc(rl)
+    out = []
+    for funcname, doc in q:
+        out.append(funcname)
+        out.append("\n".join(textwrap.wrap(doc, 80, initial_indent="   ")))
+        out.append("")
+    return out     
\ No newline at end of file
diff --git a/pyreadline/keysyms/__init__.py b/pyreadline/keysyms/__init__.py
new file mode 100644
index 0000000..062414a
--- /dev/null
+++ b/pyreadline/keysyms/__init__.py
@@ -0,0 +1,20 @@
+import sys
+
+success = False
+in_ironpython = "IronPython" in sys.version
+
+if in_ironpython:
+    try:
+        from .ironpython_keysyms import *
+        success = True
+    except ImportError as x:
+        raise
+else:
+    try:
+        from .keysyms import *
+        success = True
+    except ImportError as x:
+        pass
+    
+if not success:
+    raise ImportError("Could not import keysym for local pythonversion", x)
\ No newline at end of file
diff --git a/pyreadline/keysyms/common.py b/pyreadline/keysyms/common.py
new file mode 100644
index 0000000..63a9977
--- /dev/null
+++ b/pyreadline/keysyms/common.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+# table for translating virtual keys to X windows key symbols
+
+try:
+    set
+except NameError:
+    from sets import Set as set
+    
+from pyreadline.unicode_helper import ensure_unicode
+
+validkey =set(['cancel',      'backspace',    'tab',          'clear',
+               'return',      'shift_l',      'control_l',    'alt_l',
+               'pause',       'caps_lock',    'escape',       'space',
+               'prior',       'next',         'end',          'home',
+               'left',        'up',           'right',        'down',
+               'select',      'print',        'execute',      'snapshot',
+               'insert',      'delete',       'help',         'f1',
+               'f2',          'f3',           'f4',           'f5',
+               'f6',          'f7',           'f8',           'f9',
+               'f10',         'f11',          'f12',          'f13',
+               'f14',         'f15',          'f16',          'f17',
+               'f18',         'f19',          'f20',          'f21',
+               'f22',         'f23',          'f24',          'num_lock',
+               'scroll_lock', 'vk_apps',      'vk_processkey','vk_attn',
+               'vk_crsel',    'vk_exsel',     'vk_ereof',     'vk_play',
+               'vk_zoom',     'vk_noname',    'vk_pa1',       'vk_oem_clear',
+               'numpad0',     'numpad1',      'numpad2',      'numpad3',
+               'numpad4',     'numpad5',      'numpad6',      'numpad7',
+               'numpad8',     'numpad9',      'divide',       'multiply',
+               'add',         'subtract',     'vk_decimal'])
+
+escape_sequence_to_special_key = {"\\e[a" : "up", "\\e[b" : "down", "del" : "delete"}
+
+class KeyPress(object):
+    def __init__(self, char="", shift=False, control=False, meta=False, keyname=""):
+        if control or meta or shift:
+            char = char.upper()
+        self.info = dict(char=char,
+                         shift=shift,
+                         control=control,
+                         meta=meta,
+                         keyname=keyname)
+        
+    def create(name):
+        def get(self):
+            return self.info[name]
+
+        def set(self, value):
+            self.info[name] = value
+        return property(get, set)
+    char = create("char")
+    shift = create("shift")
+    control = create("control")
+    meta = create("meta")
+    keyname = create("keyname")
+        
+    def __repr__(self):
+        return "(%s,%s,%s,%s)"%tuple(map(ensure_unicode, self.tuple()))
+
+    def tuple(self):
+        if self.keyname:
+            return (self.control, self.meta, self.shift, self.keyname)
+        else:
+            if self.control or self.meta or self.shift:
+                return (self.control, self.meta, self.shift, self.char.upper())
+            else:
+                return (self.control, self.meta, self.shift, self.char)
+
+    def __eq__(self, other):
+        if isinstance(other, KeyPress):
+            s = self.tuple()
+            o = other.tuple()
+            return s == o
+        else:
+            return False
+
+def make_KeyPress_from_keydescr(keydescr):
+    keyinfo = KeyPress()
+    if len(keydescr) > 2 and keydescr[:1] == '"' and keydescr[-1:] == '"':
+        keydescr = keydescr[1:-1]
+        
+    while 1:
+        lkeyname = keydescr.lower()
+        if lkeyname.startswith('control-'):
+            keyinfo.control = True
+            keydescr = keydescr[8:]
+        elif lkeyname.startswith('ctrl-'):
+            keyinfo.control = True
+            keydescr = keydescr[5:]
+        elif keydescr.lower().startswith('\\c-'):
+            keyinfo.control = True
+            keydescr = keydescr[3:]
+        elif keydescr.lower().startswith('\\m-'):
+            keyinfo.meta = True
+            keydescr = keydescr[3:]
+        elif keydescr in escape_sequence_to_special_key:
+            keydescr = escape_sequence_to_special_key[keydescr]
+        elif lkeyname.startswith('meta-'):
+            keyinfo.meta = True
+            keydescr = keydescr[5:]
+        elif lkeyname.startswith('alt-'):
+            keyinfo.meta = True
+            keydescr = keydescr[4:]
+        elif lkeyname.startswith('shift-'):
+            keyinfo.shift = True
+            keydescr = keydescr[6:]
+        else:
+            if len(keydescr) > 1:
+                if keydescr.strip().lower() in validkey:
+                    keyinfo.keyname = keydescr.strip().lower()
+                    keyinfo.char = ""
+                else:
+                    raise IndexError("Not a valid key: '%s'"%keydescr)
+            else:
+                keyinfo.char = keydescr
+            return keyinfo
+
+if __name__ == "__main__":
+    import startup
+    
\ No newline at end of file
diff --git a/pyreadline/keysyms/ironpython_keysyms.py b/pyreadline/keysyms/ironpython_keysyms.py
new file mode 100644
index 0000000..4cdd67c
--- /dev/null
+++ b/pyreadline/keysyms/ironpython_keysyms.py
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import System
+from .common import validkey, KeyPress, make_KeyPress_from_keydescr
+
+c32 = System.ConsoleKey
+Shift = System.ConsoleModifiers.Shift
+Control = System.ConsoleModifiers.Control
+Alt = System.ConsoleModifiers.Alt
+# table for translating virtual keys to X windows key symbols
+code2sym_map = {#c32.CANCEL:    u'Cancel',
+                c32.Backspace:  'BackSpace',
+                c32.Tab:        'Tab',
+                c32.Clear:      'Clear',
+                c32.Enter:      'Return',
+#                c32.Shift:     u'Shift_L',
+#                c32.Control:   u'Control_L',
+#                c32.Menu:      u'Alt_L',
+                c32.Pause:      'Pause',
+#                c32.Capital:   u'Caps_Lock',
+                c32.Escape:     'Escape',
+#                c32.Space:     u'space',
+                c32.PageUp:     'Prior',
+                c32.PageDown:   'Next',
+                c32.End:        'End',
+                c32.Home:       'Home',
+                c32.LeftArrow:  'Left',
+                c32.UpArrow:    'Up',
+                c32.RightArrow: 'Right',
+                c32.DownArrow:  'Down',
+                c32.Select:     'Select',
+                c32.Print:      'Print',
+                c32.Execute:    'Execute',
+#                c32.Snapshot:  u'Snapshot',
+                c32.Insert:     'Insert',
+                c32.Delete:     'Delete',
+                c32.Help:       'Help',
+                c32.F1:         'F1',
+                c32.F2:         'F2',
+                c32.F3:         'F3',
+                c32.F4:         'F4',
+                c32.F5:         'F5',
+                c32.F6:         'F6',
+                c32.F7:         'F7',
+                c32.F8:         'F8',
+                c32.F9:         'F9',
+                c32.F10:        'F10',
+                c32.F11:        'F11',
+                c32.F12:        'F12',
+                c32.F13:        'F13',
+                c32.F14:        'F14',
+                c32.F15:        'F15',
+                c32.F16:        'F16',
+                c32.F17:        'F17',
+                c32.F18:        'F18',
+                c32.F19:        'F19',
+                c32.F20:        'F20',
+                c32.F21:        'F21',
+                c32.F22:        'F22',
+                c32.F23:        'F23',
+                c32.F24:        'F24',
+#                c32.Numlock:    u'Num_Lock,',
+#                c32.Scroll:     u'Scroll_Lock',
+#                c32.Apps:       u'VK_APPS',
+#                c32.ProcesskeY: u'VK_PROCESSKEY',
+#                c32.Attn:       u'VK_ATTN',
+#                c32.Crsel:      u'VK_CRSEL',
+#                c32.Exsel:      u'VK_EXSEL',
+#                c32.Ereof:      u'VK_EREOF',
+#                c32.Play:       u'VK_PLAY',
+#                c32.Zoom:       u'VK_ZOOM',
+#                c32.Noname:     u'VK_NONAME',
+#                c32.Pa1:        u'VK_PA1',
+                c32.OemClear:  'VK_OEM_CLEAR',
+                c32.NumPad0:    'NUMPAD0',
+                c32.NumPad1:    'NUMPAD1',
+                c32.NumPad2:    'NUMPAD2',
+                c32.NumPad3:    'NUMPAD3',
+                c32.NumPad4:    'NUMPAD4',
+                c32.NumPad5:    'NUMPAD5',
+                c32.NumPad6:    'NUMPAD6',
+                c32.NumPad7:    'NUMPAD7',
+                c32.NumPad8:    'NUMPAD8',
+                c32.NumPad9:    'NUMPAD9',
+                c32.Divide:     'Divide',
+                c32.Multiply:   'Multiply',
+                c32.Add:        'Add',
+                c32.Subtract:   'Subtract',
+                c32.Decimal:    'VK_DECIMAL'
+               }
+
+# function to handle the mapping
+def make_keysym(keycode):
+    try:
+        sym = code2sym_map[keycode]
+    except KeyError:
+        sym = ''
+    return sym
+
+sym2code_map = {}
+for code,sym in code2sym_map.items():
+    sym2code_map[sym.lower()] = code
+
+def key_text_to_keyinfo(keytext):
+    '''Convert a GNU readline style textual description of a key to keycode with modifiers'''
+    if keytext.startswith('"'): # "
+        return keyseq_to_keyinfo(keytext[1:-1])
+    else:
+        return keyname_to_keyinfo(keytext)
+
+
+def char_to_keyinfo(char, control=False, meta=False, shift=False):
+    vk = (ord(char))
+    if vk & 0xffff == 0xffff:
+        print('VkKeyScan("%s") = %x' % (char, vk))
+        raise ValueError('bad key')
+    if vk & 0x100:
+        shift = True
+    if vk & 0x200:
+        control = True
+    if vk & 0x400:
+        meta = True
+    return (control, meta, shift, vk & 0xff)
+
+def keyname_to_keyinfo(keyname):
+    control = False
+    meta = False
+    shift = False
+
+    while 1:
+        lkeyname = keyname.lower()
+        if lkeyname.startswith('control-'):
+            control = True
+            keyname = keyname[8:]
+        elif lkeyname.startswith('ctrl-'):
+            control = True
+            keyname = keyname[5:]
+        elif lkeyname.startswith('meta-'):
+            meta = True
+            keyname = keyname[5:]
+        elif lkeyname.startswith('alt-'):
+            meta = True
+            keyname = keyname[4:]
+        elif lkeyname.startswith('shift-'):
+            shift = True
+            keyname = keyname[6:]
+        else:
+            if len(keyname) > 1:
+                return (control, meta, shift, sym2code_map.get(keyname.lower()," "))
+            else:
+                return char_to_keyinfo(keyname, control, meta, shift)
+
+def keyseq_to_keyinfo(keyseq):
+    res = []
+    control = False
+    meta = False
+    shift = False
+
+    while 1:
+        if keyseq.startswith('\\C-'):
+            control = True
+            keyseq = keyseq[3:]
+        elif keyseq.startswith('\\M-'):
+            meta = True
+            keyseq = keyseq[3:]
+        elif keyseq.startswith('\\e'):
+            res.append(char_to_keyinfo('\033', control, meta, shift))
+            control = meta = shift = False
+            keyseq = keyseq[2:]
+        elif len(keyseq) >= 1:
+            res.append(char_to_keyinfo(keyseq[0], control, meta, shift))
+            control = meta = shift = False
+            keyseq = keyseq[1:]
+        else:
+            return res[0]
+
+def make_keyinfo(keycode, state):
+    control = False
+    meta  =False
+    shift = False
+    return (control, meta, shift, keycode)
+
+
+def make_KeyPress(char, state, keycode):
+
+    shift = bool(int(state) & int(Shift))
+    control = bool(int(state) & int(Control))
+    meta = bool(int(state) & int(Alt))
+    keyname = code2sym_map.get(keycode, "").lower()
+    if control and meta: #equivalent to altgr so clear flags
+        control = False
+        meta = False    
+    elif control:
+        char = str(keycode)
+    return KeyPress(char, shift, control, meta, keyname)
+
diff --git a/pyreadline/keysyms/keysyms.py b/pyreadline/keysyms/keysyms.py
new file mode 100644
index 0000000..33d971f
--- /dev/null
+++ b/pyreadline/keysyms/keysyms.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+from . import winconstants as c32
+from   pyreadline.logger import log
+from ctypes import windll
+import ctypes
+# table for translating virtual keys to X windows key symbols
+
+from .common import validkey, KeyPress, make_KeyPress_from_keydescr
+
+code2sym_map = {c32.VK_CANCEL:     'cancel',
+                c32.VK_BACK:       'backspace',
+                c32.VK_TAB:        'tab',
+                c32.VK_CLEAR:      'clear',
+                c32.VK_RETURN:     'return',
+                c32.VK_SHIFT:      'shift_l',
+                c32.VK_CONTROL:    'control_l',
+                c32.VK_MENU:       'alt_l',
+                c32.VK_PAUSE:      'pause',
+                c32.VK_CAPITAL:    'caps_lock',
+                c32.VK_ESCAPE:     'escape',
+                c32.VK_SPACE:      'space',
+                c32.VK_PRIOR:      'prior',
+                c32.VK_NEXT:       'next',
+                c32.VK_END:        'end',
+                c32.VK_HOME:       'home',
+                c32.VK_LEFT:       'left',
+                c32.VK_UP:         'up',
+                c32.VK_RIGHT:      'right',
+                c32.VK_DOWN:       'down',
+                c32.VK_SELECT:     'select',
+                c32.VK_PRINT:      'print',
+                c32.VK_EXECUTE:    'execute',
+                c32.VK_SNAPSHOT:   'snapshot',
+                c32.VK_INSERT:     'insert',
+                c32.VK_DELETE:     'delete',
+                c32.VK_HELP:       'help',
+                c32.VK_F1:         'f1',
+                c32.VK_F2:         'f2',
+                c32.VK_F3:         'f3',
+                c32.VK_F4:         'f4',
+                c32.VK_F5:         'f5',
+                c32.VK_F6:         'f6',
+                c32.VK_F7:         'f7',
+                c32.VK_F8:         'f8',
+                c32.VK_F9:         'f9',
+                c32.VK_F10:        'f10',
+                c32.VK_F11:        'f11',
+                c32.VK_F12:        'f12',
+                c32.VK_F13:        'f13',
+                c32.VK_F14:        'f14',
+                c32.VK_F15:        'f15',
+                c32.VK_F16:        'f16',
+                c32.VK_F17:        'f17',
+                c32.VK_F18:        'f18',
+                c32.VK_F19:        'f19',
+                c32.VK_F20:        'f20',
+                c32.VK_F21:        'f21',
+                c32.VK_F22:        'f22',
+                c32.VK_F23:        'f23',
+                c32.VK_F24:        'f24',
+                c32.VK_NUMLOCK:    'num_lock,',
+                c32.VK_SCROLL:     'scroll_lock',
+                c32.VK_APPS:       'vk_apps',
+                c32.VK_PROCESSKEY: 'vk_processkey',
+                c32.VK_ATTN:       'vk_attn',
+                c32.VK_CRSEL:      'vk_crsel',
+                c32.VK_EXSEL:      'vk_exsel',
+                c32.VK_EREOF:      'vk_ereof',
+                c32.VK_PLAY:       'vk_play',
+                c32.VK_ZOOM:       'vk_zoom',
+                c32.VK_NONAME:     'vk_noname',
+                c32.VK_PA1:        'vk_pa1',
+                c32.VK_OEM_CLEAR:  'vk_oem_clear',
+                c32.VK_NUMPAD0:    'numpad0',
+                c32.VK_NUMPAD1:    'numpad1',
+                c32.VK_NUMPAD2:    'numpad2',
+                c32.VK_NUMPAD3:    'numpad3',
+                c32.VK_NUMPAD4:    'numpad4',
+                c32.VK_NUMPAD5:    'numpad5',
+                c32.VK_NUMPAD6:    'numpad6',
+                c32.VK_NUMPAD7:    'numpad7',
+                c32.VK_NUMPAD8:    'numpad8',
+                c32.VK_NUMPAD9:    'numpad9',
+                c32.VK_DIVIDE:     'divide',
+                c32.VK_MULTIPLY:   'multiply',
+                c32.VK_ADD:        'add',
+                c32.VK_SUBTRACT:   'subtract',
+                c32.VK_DECIMAL:    'vk_decimal'
+               }
+
+VkKeyScan = windll.user32.VkKeyScanA
+
+def char_to_keyinfo(char, control=False, meta=False, shift=False):
+    k=KeyPress()
+    vk = VkKeyScan(ord(char))
+    if vk & 0xffff == 0xffff:
+        print('VkKeyScan("%s") = %x' % (char, vk))
+        raise ValueError('bad key')
+    if vk & 0x100:
+        k.shift = True
+    if vk & 0x200:
+        k.control = True
+    if vk & 0x400:
+        k.meta = True
+    k.char=chr(vk & 0xff)
+    return k
+
+def make_KeyPress(char, state, keycode):
+    control = (state & (4+8)) != 0
+    meta = (state & (1+2)) != 0
+    shift = (state & 0x10) != 0
+    if control and not meta:#Matches ctrl- chords should pass keycode as char
+        char = chr(keycode)
+    elif control and meta:  #Matches alt gr and should just pass on char
+        control = False
+        meta = False
+    try:
+        keyname=code2sym_map[keycode]
+    except KeyError:
+        keyname = ""
+    out = KeyPress(char, shift, control, meta, keyname)
+    return out
+
+if __name__=="__main__":
+    import startup
+    
\ No newline at end of file
diff --git a/pyreadline/keysyms/winconstants.py b/pyreadline/keysyms/winconstants.py
new file mode 100644
index 0000000..5e0ed63
--- /dev/null
+++ b/pyreadline/keysyms/winconstants.py
@@ -0,0 +1,171 @@
+#This file contains constants that are normally found in win32all
+#But included here to avoid the dependency
+
+VK_LBUTTON=1
+VK_RBUTTON=2
+VK_CANCEL=3
+VK_MBUTTON=4
+VK_XBUTTON1=5
+VK_XBUTTON2=6
+VK_BACK=8
+VK_TAB=9
+VK_CLEAR=12
+VK_RETURN=13
+VK_SHIFT=16
+VK_CONTROL=17
+VK_MENU=18
+VK_PAUSE=19
+VK_CAPITAL=20
+VK_KANA=0x15
+VK_HANGEUL=0x15
+VK_HANGUL=0x15
+VK_JUNJA=0x17
+VK_FINAL=0x18
+VK_HANJA=0x19
+VK_KANJI=0x19
+VK_ESCAPE=0x1B
+VK_CONVERT=0x1C
+VK_NONCONVERT=0x1D
+VK_ACCEPT=0x1E
+VK_MODECHANGE=0x1F
+VK_SPACE=32
+VK_PRIOR=33
+VK_NEXT=34
+VK_END=35
+VK_HOME=36
+VK_LEFT=37
+VK_UP=38
+VK_RIGHT=39
+VK_DOWN=40
+VK_SELECT=41
+VK_PRINT=42
+VK_EXECUTE=43
+VK_SNAPSHOT=44
+VK_INSERT=45
+VK_DELETE=46
+VK_HELP=47
+VK_LWIN=0x5B
+VK_RWIN=0x5C
+VK_APPS=0x5D
+VK_SLEEP=0x5F
+VK_NUMPAD0=0x60
+VK_NUMPAD1=0x61
+VK_NUMPAD2=0x62
+VK_NUMPAD3=0x63
+VK_NUMPAD4=0x64
+VK_NUMPAD5=0x65
+VK_NUMPAD6=0x66
+VK_NUMPAD7=0x67
+VK_NUMPAD8=0x68
+VK_NUMPAD9=0x69
+VK_MULTIPLY=0x6A
+VK_ADD=0x6B
+VK_SEPARATOR=0x6C
+VK_SUBTRACT=0x6D
+VK_DECIMAL=0x6E
+VK_DIVIDE=0x6F
+VK_F1=0x70
+VK_F2=0x71
+VK_F3=0x72
+VK_F4=0x73
+VK_F5=0x74
+VK_F6=0x75
+VK_F7=0x76
+VK_F8=0x77
+VK_F9=0x78
+VK_F10=0x79
+VK_F11=0x7A
+VK_F12=0x7B
+VK_F13=0x7C
+VK_F14=0x7D
+VK_F15=0x7E
+VK_F16=0x7F
+VK_F17=0x80
+VK_F18=0x81
+VK_F19=0x82
+VK_F20=0x83
+VK_F21=0x84
+VK_F22=0x85
+VK_F23=0x86
+VK_F24=0x87
+VK_NUMLOCK=0x90
+VK_SCROLL=0x91
+VK_LSHIFT=0xA0
+VK_RSHIFT=0xA1
+VK_LCONTROL=0xA2
+VK_RCONTROL=0xA3
+VK_LMENU=0xA4
+VK_RMENU=0xA5
+VK_BROWSER_BACK=0xA6
+VK_BROWSER_FORWARD=0xA7
+VK_BROWSER_REFRESH=0xA8
+VK_BROWSER_STOP=0xA9
+VK_BROWSER_SEARCH=0xAA
+VK_BROWSER_FAVORITES=0xAB
+VK_BROWSER_HOME=0xAC
+VK_VOLUME_MUTE=0xAD
+VK_VOLUME_DOWN=0xAE
+VK_VOLUME_UP=0xAF
+VK_MEDIA_NEXT_TRACK=0xB0
+VK_MEDIA_PREV_TRACK=0xB1
+VK_MEDIA_STOP=0xB2
+VK_MEDIA_PLAY_PAUSE=0xB3
+VK_LAUNCH_MAIL=0xB4
+VK_LAUNCH_MEDIA_SELECT=0xB5
+VK_LAUNCH_APP1=0xB6
+VK_LAUNCH_APP2=0xB7
+VK_OEM_1=0xBA
+VK_OEM_PLUS=0xBB
+VK_OEM_COMMA=0xBC
+VK_OEM_MINUS=0xBD
+VK_OEM_PERIOD=0xBE
+VK_OEM_2=0xBF
+VK_OEM_3=0xC0
+VK_OEM_4=0xDB
+VK_OEM_5=0xDC
+VK_OEM_6=0xDD
+VK_OEM_7=0xDE
+VK_OEM_8=0xDF
+VK_OEM_102=0xE2
+VK_PROCESSKEY=0xE5
+VK_PACKET=0xE7
+VK_ATTN=0xF6
+VK_CRSEL=0xF7
+VK_EXSEL=0xF8
+VK_EREOF=0xF9
+VK_PLAY=0xFA
+VK_ZOOM=0xFB
+VK_NONAME=0xFC
+VK_PA1=0xFD
+VK_OEM_CLEAR=0xFE
+
+CF_TEXT=1
+CF_BITMAP=2
+CF_METAFILEPICT=3
+CF_SYLK=4
+CF_DIF=5
+CF_TIFF=6
+CF_OEMTEXT=7
+CF_DIB=8
+CF_PALETTE=9
+CF_PENDATA=10
+CF_RIFF=11
+CF_WAVE=12
+CF_UNICODETEXT=13
+CF_ENHMETAFILE=14
+CF_HDROP=15
+CF_LOCALE=16
+CF_MAX=17
+CF_OWNERDISPLAY=128
+CF_DSPTEXT=129
+CF_DSPBITMAP=130
+CF_DSPMETAFILEPICT=131
+CF_DSPENHMETAFILE=142
+CF_PRIVATEFIRST=512
+CF_PRIVATELAST=767
+CF_GDIOBJFIRST=768
+CF_GDIOBJLAST=1023
+
+
+GPTR=64
+GHND=66
diff --git a/pyreadline/lineeditor/__init__.py b/pyreadline/lineeditor/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyreadline/lineeditor/history.py b/pyreadline/lineeditor/history.py
new file mode 100644
index 0000000..d3d4b71
--- /dev/null
+++ b/pyreadline/lineeditor/history.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import re, operator,string, sys,os
+
+from pyreadline.unicode_helper import ensure_unicode, ensure_str
+if "pyreadline" in sys.modules:
+    pyreadline = sys.modules["pyreadline"]
+else:
+    import pyreadline
+
+from . import lineobj
+
+class EscapeHistory(Exception):
+    pass
+
+from pyreadline.logger import log
+
+
+class LineHistory(object):
+    def __init__(self):
+        self.history = []
+        self._history_length = 100
+        self._history_cursor = 0
+        self.history_filename = os.path.expanduser('~/.history') #Cannot expand unicode strings correctly on python2.4
+        self.lastcommand = None
+        self.query = ""
+        self.last_search_for = ""
+
+    def get_current_history_length(self):
+        '''Return the number of lines currently in the history.
+        (This is different from get_history_length(), which returns 
+        the maximum number of lines that will be written to a history file.)'''
+        value = len(self.history)
+        log("get_current_history_length:%d"%value)
+        return value
+
+    def get_history_length(self):
+        '''Return the desired length of the history file. Negative values imply
+        unlimited history file size.'''
+        value = self._history_length
+        log("get_history_length:%d"%value)
+        return value
+
+    def get_history_item(self, index):
+        '''Return the current contents of history item at index (starts with index 1).'''
+        item = self.history[index - 1]
+        log("get_history_item: index:%d item:%r"%(index, item))
+        return item.get_line_text()
+
+    def set_history_length(self, value):
+        log("set_history_length: old:%d new:%d"%(self._history_length, value))
+        self._history_length = value
+
+    def get_history_cursor(self):
+        value = self._history_cursor
+        log("get_history_cursor:%d"%value)
+        return value
+
+    def set_history_cursor(self, value):
+        log("set_history_cursor: old:%d new:%d"%(self._history_cursor, value))
+        self._history_cursor = value
+        
+    history_length = property(get_history_length, set_history_length)
+    history_cursor = property(get_history_cursor, set_history_cursor)
+
+    def clear_history(self):
+        '''Clear readline history.'''
+        self.history[:] = []
+        self.history_cursor = 0
+
+    def read_history_file(self, filename=None): 
+        '''Load a readline history file.'''
+        if filename is None:
+            filename = self.history_filename
+        try:
+            for line in open(filename, 'r'):
+                self.add_history(lineobj.ReadLineTextBuffer(ensure_unicode(line.rstrip())))
+        except IOError:
+            self.history = []
+            self.history_cursor = 0
+
+    def write_history_file(self, filename = None): 
+        '''Save a readline history file.'''
+        if filename is None:
+            filename = self.history_filename
+        fp = open(filename, 'wb')
+        for line in self.history[-self.history_length:]:
+            fp.write(ensure_str(line.get_line_text()))
+            fp.write('\n'.encode('ascii'))
+        fp.close()
+
+
+    def add_history(self, line):
+        '''Append a line to the history buffer, as if it was the last line typed.'''
+        if not hasattr(line, "get_line_text"):
+            line = lineobj.ReadLineTextBuffer(line)
+        if not line.get_line_text():
+            pass
+        elif len(self.history) > 0 and self.history[-1].get_line_text() == line.get_line_text():
+            pass
+        else:
+            self.history.append(line)
+        self.history_cursor = len(self.history)
+
+    def previous_history(self, current): # (C-p)
+        '''Move back through the history list, fetching the previous command. '''
+        if self.history_cursor == len(self.history):
+            self.history.append(current.copy()) #do not use add_history since we do not want to increment cursor
+            
+        if self.history_cursor > 0:
+            self.history_cursor -= 1
+            current.set_line(self.history[self.history_cursor].get_line_text())
+            current.point = lineobj.EndOfLine
+
+    def next_history(self, current): # (C-n)
+        '''Move forward through the history list, fetching the next command. '''
+        if self.history_cursor < len(self.history) - 1:
+            self.history_cursor += 1
+            current.set_line(self.history[self.history_cursor].get_line_text())
+
+    def beginning_of_history(self): # (M-<)
+        '''Move to the first line in the history.'''
+        self.history_cursor = 0
+        if len(self.history) > 0:
+            self.l_buffer = self.history[0]
+
+    def end_of_history(self, current): # (M->)
+        '''Move to the end of the input history, i.e., the line currently
+        being entered.'''
+        self.history_cursor = len(self.history)
+        current.set_line(self.history[-1].get_line_text())
+
+    def reverse_search_history(self, searchfor, startpos=None):
+        if startpos is None:
+            startpos = self.history_cursor
+        origpos = startpos
+
+        result =  lineobj.ReadLineTextBuffer("")
+
+        for idx, line in list(enumerate(self.history))[startpos:0:-1]:
+            if searchfor in line:
+                startpos = idx
+                break
+
+        #If we get a new search without change in search term it means
+        #someone pushed ctrl-r and we should find the next match
+        if self.last_search_for == searchfor and startpos > 0:
+            startpos -= 1
+            for idx, line in list(enumerate(self.history))[startpos:0:-1]:
+                if searchfor in line:
+                    startpos = idx
+                    break
+
+        if self.history:                    
+            result = self.history[startpos].get_line_text()
+        else:
+            result = ""
+        self.history_cursor = startpos
+        self.last_search_for = searchfor
+        log("reverse_search_history: old:%d new:%d result:%r"%(origpos, self.history_cursor, result))
+        return result
+        
+    def forward_search_history(self, searchfor, startpos=None):
+        if startpos is None:
+            startpos = min(self.history_cursor, max(0, self.get_current_history_length()-1))
+        origpos = startpos
+        
+        result =  lineobj.ReadLineTextBuffer("")
+
+        for idx, line in list(enumerate(self.history))[startpos:]:
+            if searchfor in line:
+                startpos = idx
+                break
+
+        #If we get a new search without change in search term it means
+        #someone pushed ctrl-r and we should find the next match
+        if self.last_search_for == searchfor and startpos < self.get_current_history_length()-1:
+            startpos += 1
+            for idx, line in list(enumerate(self.history))[startpos:]:
+                if searchfor in line:
+                    startpos = idx
+                    break
+
+        if self.history:                    
+            result = self.history[startpos].get_line_text()
+        else:
+            result = ""
+        self.history_cursor = startpos
+        self.last_search_for = searchfor
+        return result
+
+    def _search(self, direction, partial):
+        try:
+            if (self.lastcommand != self.history_search_forward and
+                    self.lastcommand != self.history_search_backward):
+                self.query = ''.join(partial[0:partial.point].get_line_text())
+            hcstart = max(self.history_cursor,0) 
+            hc = self.history_cursor + direction
+            while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)):
+                h = self.history[hc]
+                if not self.query:
+                    self.history_cursor = hc
+                    result = lineobj.ReadLineTextBuffer(h, point=len(h.get_line_text()))
+                    return result
+                elif (h.get_line_text().startswith(self.query) and (h != partial.get_line_text())):
+                    self.history_cursor = hc
+                    result = lineobj.ReadLineTextBuffer(h, point=partial.point)
+                    return result
+                hc += direction
+            else:
+                if len(self.history) == 0:
+                    pass 
+                elif hc >= len(self.history) and not self.query:
+                    self.history_cursor = len(self.history)
+                    return lineobj.ReadLineTextBuffer("", point=0)
+                elif self.history[max(min(hcstart, len(self.history) - 1), 0)]\
+                        .get_line_text().startswith(self.query) and self.query:
+                    return lineobj.ReadLineTextBuffer(self.history\
+                            [max(min(hcstart, len(self.history) - 1),0)],
+                                point = partial.point)
+                else:                
+                    return lineobj.ReadLineTextBuffer(partial, 
+                                                      point=partial.point)
+                return lineobj.ReadLineTextBuffer(self.query, 
+                                                  point=min(len(self.query),
+                                                  partial.point))
+        except IndexError:
+            raise
+
+    def history_search_forward(self, partial): # ()
+        '''Search forward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        q= self._search(1, partial)
+        return q
+
+    def history_search_backward(self, partial): # ()
+        '''Search backward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        
+        q= self._search(-1, partial)
+        return q
+
+if __name__=="__main__":
+    import pdb
+    q = LineHistory()
+    r = LineHistory()
+    s = LineHistory()
+    RL = lineobj.ReadLineTextBuffer
+    q.add_history(RL("aaaa"))
+    q.add_history(RL("aaba"))
+    q.add_history(RL("aaca"))
+    q.add_history(RL("akca"))
+    q.add_history(RL("bbb"))
+    q.add_history(RL("ako"))
+    r.add_history(RL("ako"))
diff --git a/pyreadline/lineeditor/lineobj.py b/pyreadline/lineeditor/lineobj.py
new file mode 100644
index 0000000..dedc8b1
--- /dev/null
+++ b/pyreadline/lineeditor/lineobj.py
@@ -0,0 +1,799 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import re, operator, sys
+
+from . import wordmatcher
+import pyreadline.clipboard as clipboard
+from pyreadline.logger import  log
+from pyreadline.unicode_helper import ensure_unicode, biter
+
+kill_ring_to_clipboard = False #set to true to copy every addition to kill ring to clipboard
+
+
+class NotAWordError(IndexError):
+    pass
+
+
+def quote_char(c):
+    if ord(c) > 0:
+        return c
+
+############## Line positioner ########################
+
+class LinePositioner(object):
+    def __call__(self, line):
+        NotImplementedError("Base class !!!")
+
+class NextChar(LinePositioner):
+    def __call__(self, line):
+        if line.point < len(line.line_buffer):
+            return line.point + 1
+        else:
+            return line.point
+NextChar = NextChar()
+
+class PrevChar(LinePositioner):
+    def __call__(self, line):
+        if line.point > 0:
+            return line.point - 1
+        else:
+            return line.point
+PrevChar = PrevChar()
+
+class NextWordStart(LinePositioner):
+    def __call__(self, line):
+        return line.next_start_segment(line.line_buffer, line.is_word_token)[line.point]
+NextWordStart = NextWordStart()
+
+class NextWordEnd(LinePositioner):
+    def __call__(self, line):
+        return line.next_end_segment(line.line_buffer, line.is_word_token)[line.point]
+NextWordEnd = NextWordEnd()
+
+class PrevWordStart(LinePositioner):
+    def __call__(self, line):
+        return line.prev_start_segment(line.line_buffer, line.is_word_token)[line.point]
+PrevWordStart = PrevWordStart()
+
+
+class WordStart(LinePositioner):
+    def __call__(self, line):
+        if line.is_word_token(line.get_line_text()[Point(line):Point(line) + 1]):
+            if Point(line) > 0 and line.is_word_token(line.get_line_text()[Point(line) - 1:Point(line)]):
+                return PrevWordStart(line)
+            else:
+                return line.point
+        else:   
+            raise NotAWordError("Point is not in a word")
+WordStart = WordStart()
+
+class WordEnd(LinePositioner):
+    def __call__(self, line):
+        if line.is_word_token(line.get_line_text()[Point(line):Point(line) + 1]):
+            if line.is_word_token(line.get_line_text()[Point(line) + 1:Point(line) + 2]):
+                return NextWordEnd(line)
+            else:
+                return line.point
+        else:   
+            raise NotAWordError("Point is not in a word")
+WordEnd = WordEnd()
+
+class PrevWordEnd(LinePositioner):
+    def __call__(self, line):
+        return line.prev_end_segment(line.line_buffer, line.is_word_token)[line.point]
+PrevWordEnd = PrevWordEnd()
+
+class PrevSpace(LinePositioner):
+    def __call__(self, line):
+        point = line.point
+        if line[point - 1:point].get_line_text() == " ":
+            while point > 0 and line[point - 1:point].get_line_text() == " ":
+                point -= 1
+        while point > 0 and line[point - 1:point].get_line_text() != " ":
+            point -= 1
+        return point
+PrevSpace = PrevSpace()
+
+
+class StartOfLine(LinePositioner):
+    def __call__(self, line):
+        return 0
+StartOfLine = StartOfLine()
+
+class EndOfLine(LinePositioner):
+    def __call__(self, line):
+        return len(line.line_buffer)
+EndOfLine = EndOfLine()
+
+class Point(LinePositioner):
+    def __call__(self, line):
+        return line.point
+Point = Point()
+
+class Mark(LinePositioner):
+    def __call__(self, line):
+        return line.mark
+k = Mark()
+
+all_positioners = [(value.__class__.__name__, value) 
+                        for key, value in list(globals().items()) 
+                         if isinstance(value, LinePositioner)]
+all_positioners.sort()
+
+############### LineSlice #################
+
+class LineSlice(object):
+    def __call__(self, line):
+        NotImplementedError("Base class !!!")
+
+
+class CurrentWord(LineSlice):
+    def __call__(self, line):
+        return slice(WordStart(line), WordEnd(line), None)
+CurrentWord = CurrentWord()
+
+class NextWord(LineSlice):
+    def __call__(self, line):
+        work = TextLine(line)
+        work.point = NextWordStart
+        start = work.point
+        stop = NextWordEnd(work)
+        return slice(start, stop)
+NextWord = NextWord()
+
+class PrevWord(LineSlice):
+    def __call__(self, line):
+        work = TextLine(line)
+        work.point = PrevWordEnd
+        stop = work.point
+        start = PrevWordStart(work)
+        return slice(start, stop)
+PrevWord = PrevWord()
+
+class PointSlice(LineSlice):
+    def __call__(self, line):
+        return slice(Point(line), Point(line) + 1, None)
+PointSlice = PointSlice()
+
+
+###############  TextLine  ######################
+
+class TextLine(object):
+    def __init__(self, txtstr, point = None, mark = None):
+        self.line_buffer = []
+        self._point = 0
+        self.mark = -1
+        self.undo_stack = []
+        self.overwrite = False
+        if isinstance(txtstr, TextLine): #copy 
+            self.line_buffer = txtstr.line_buffer[:]
+            if point is None:
+                self.point = txtstr.point
+            else:                
+                self.point = point
+            if mark is None:
+                self.mark = txtstr.mark
+            else:
+                self.mark = mark
+        else:            
+            self._insert_text(txtstr)
+            if point is None:
+                self.point = 0
+            else:
+                self.point = point
+            if mark is None:
+                self.mark = -1
+            else:
+                self.mark = mark
+
+        self.is_word_token = wordmatcher.is_word_token
+        self.next_start_segment = wordmatcher.next_start_segment
+        self.next_end_segment = wordmatcher.next_end_segment
+        self.prev_start_segment = wordmatcher.prev_start_segment
+        self.prev_end_segment = wordmatcher.prev_end_segment
+        
+    def push_undo(self):
+        ltext = self.get_line_text()
+        if self.undo_stack and ltext == self.undo_stack[-1].get_line_text():
+            self.undo_stack[-1].point = self.point
+        else:
+            self.undo_stack.append(self.copy())
+
+    def pop_undo(self):
+        if len(self.undo_stack) >= 2:
+            self.undo_stack.pop()
+            self.set_top_undo()
+            self.undo_stack.pop()
+        else:
+            self.reset_line()
+            self.undo_stack = []
+
+    def set_top_undo(self):
+        if self.undo_stack:
+            undo = self.undo_stack[-1]
+            self.line_buffer = undo.line_buffer
+            self.point = undo.point
+            self.mark = undo.mark
+        else:
+            pass
+        
+    def __repr__(self):
+        return 'TextLine("%s",point=%s,mark=%s)'%(self.line_buffer, self.point, self.mark)
+
+    def copy(self):
+        return self.__class__(self)
+
+    def set_point(self,value):
+        if isinstance(value, LinePositioner):
+            value = value(self)
+        assert  (value <= len(self.line_buffer))           
+        if value > len(self.line_buffer):
+            value = len(self.line_buffer)
+        self._point = value
+    def get_point(self):
+        return self._point
+    point = property(get_point, set_point)
+
+
+    def visible_line_width(self, position = Point):
+        """Return the visible width of the text in line buffer up to position."""
+        extra_char_width = len([ None for c in self[:position].line_buffer if 0x2013 <= ord(c) <= 0xFFFD])
+        return len(self[:position].quoted_text()) + self[:position].line_buffer.count("\t")*7 + extra_char_width
+
+    def quoted_text(self):
+        quoted = [ quote_char(c) for c in self.line_buffer ]
+        self.line_char_width = [ len(c) for c in quoted ]
+        return ''.join(map(ensure_unicode, quoted))
+
+    def get_line_text(self):
+        buf = self.line_buffer
+        buf = list(map(ensure_unicode, buf))
+        return ''.join(buf)
+            
+    def set_line(self, text, cursor = None):
+        self.line_buffer = [ c for c in str(text) ]
+        if cursor is None:
+            self.point = len(self.line_buffer)
+        else:
+            self.point = cursor
+
+    def reset_line(self):
+        self.line_buffer = []
+        self.point = 0
+
+    def end_of_line(self):
+        self.point = len(self.line_buffer)
+
+    def _insert_text(self, text, argument=1):
+        text = text * argument
+        if self.overwrite:
+            for c in biter(text):
+                #if self.point:
+                self.line_buffer[self.point] = c
+                self.point += 1
+        else:            
+            for c in biter(text):
+                self.line_buffer.insert(self.point, c)
+                self.point += 1
+    
+    def __getitem__(self, key):
+        #Check if key is LineSlice, convert to regular slice
+        #and continue processing
+        if isinstance(key, LineSlice): 
+            key = key(self)
+        if isinstance(key, slice):
+            if key.step is None:
+                pass
+            else:
+                raise Error
+            if key.start is None:
+                start = StartOfLine(self)
+            elif isinstance(key.start,LinePositioner):
+                start = key.start(self)
+            else:
+                start = key.start
+            if key.stop is None:                   
+                stop = EndOfLine(self)
+            elif isinstance(key.stop, LinePositioner):
+                stop = key.stop(self)
+            else:
+                stop = key.stop
+            return self.__class__(self.line_buffer[start:stop], point=0)
+        elif isinstance(key, LinePositioner):
+            return self.line_buffer[key(self)]
+        elif isinstance(key, tuple):
+            raise IndexError("Cannot use step in line buffer indexing") #Multiple slice not allowed
+        else:
+            # return TextLine(self.line_buffer[key])
+            return self.line_buffer[key]
+
+    def __delitem__(self, key):
+        point = self.point
+        if isinstance(key, LineSlice):
+            key = key(self)
+        if isinstance(key, slice):
+            start = key.start
+            stop = key.stop
+            if isinstance(start, LinePositioner):
+                start = start(self)
+            elif start is None:
+                start=0
+            if isinstance(stop, LinePositioner):
+                stop = stop(self)
+            elif stop is None:
+                stop = EndOfLine(self)
+        elif isinstance(key, LinePositioner):
+            start = key(self)
+            stop = start + 1
+        else:
+            start = key
+            stop = key + 1
+        prev = self.line_buffer[:start]
+        rest = self.line_buffer[stop:]
+        self.line_buffer = prev + rest
+        if point > stop:
+            self.point = point - (stop - start)
+        elif point >= start and point <= stop:
+            self.point = start
+
+
+    def __setitem__(self, key, value):
+        if isinstance(key, LineSlice):
+            key = key(self)
+        if isinstance(key, slice):
+            start = key.start
+            stop = key.stop
+        elif isinstance(key, LinePositioner):
+            start = key(self)
+            stop = start + 1
+        else:
+            start = key
+            stop = key + 1
+        prev = self.line_buffer[:start]
+        value = self.__class__(value).line_buffer
+        rest = self.line_buffer[stop:]
+        out = prev + value + rest
+        if len(out) >= len(self):
+            self.point = len(self)
+        self.line_buffer = out
+
+    def __len__(self):
+        return len(self.line_buffer)
+
+    def upper(self):
+        self.line_buffer = [x.upper() for x in self.line_buffer]
+        return self
+
+    def lower(self):
+        self.line_buffer = [x.lower() for x in self.line_buffer]
+        return self
+        
+    def capitalize(self):
+        self.set_line(self.get_line_text().capitalize(), self.point)
+        return self
+        
+    def startswith(self, txt):
+        return self.get_line_text().startswith(txt)
+
+    def endswith(self, txt):
+        return self.get_line_text().endswith(txt)
+
+    def __contains__(self, txt):
+        return txt in self.get_line_text()
+
+
+lines = [TextLine("abc"),
+         TextLine("abc def"),
+         TextLine("abc def  ghi"),
+         TextLine("  abc  def  "),
+        ]
+l = lines[2]
+l.point = 5
+
+
+
+class ReadLineTextBuffer(TextLine):
+    def __init__(self,txtstr, point = None, mark = None):
+        super(ReadLineTextBuffer, self).__init__(txtstr, point, mark)
+        self.enable_win32_clipboard = True
+        self.selection_mark = -1
+        self.enable_selection = True
+        self.kill_ring = []
+
+    def __repr__(self):
+        return 'ReadLineTextBuffer'\
+               '("%s",point=%s,mark=%s,selection_mark=%s)'%\
+                 (self.line_buffer, self.point, self.mark,self.selection_mark)
+
+
+    def insert_text(self, char, argument=1):
+        self.delete_selection()
+        self.selection_mark = -1
+        self._insert_text(char, argument)
+    
+    def to_clipboard(self):
+        if self.enable_win32_clipboard:
+                clipboard.set_clipboard_text(self.get_line_text())
+    
+######### Movement
+
+    def beginning_of_line(self):
+        self.selection_mark = -1
+        self.point = StartOfLine
+        
+    def end_of_line(self):
+        self.selection_mark = -1
+        self.point = EndOfLine
+
+    def forward_char(self,argument = 1):
+        if argument < 0:
+            self.backward_char(-argument)
+        self.selection_mark = -1
+        for x in range(argument):
+            self.point = NextChar
+        
+    def backward_char(self, argument=1):
+        if argument < 0:
+            self.forward_char(-argument)
+        self.selection_mark = -1
+        for x in range(argument):
+            self.point = PrevChar
+        
+    def forward_word(self,argument=1):
+        if argument<0:
+            self.backward_word(-argument)
+        self.selection_mark=-1
+        for x in range(argument):
+            self.point = NextWordStart
+       
+    def backward_word(self, argument=1):
+        if argument < 0:
+            self.forward_word(-argument)
+        self.selection_mark = -1
+        for x in range(argument):
+            self.point = PrevWordStart
+
+    def forward_word_end(self, argument=1):
+        if argument < 0:
+            self.backward_word_end(-argument)
+        self.selection_mark = -1
+        for x in range(argument):
+            self.point = NextWordEnd
+
+    def backward_word_end(self, argument=1):
+        if argument < 0:
+            self.forward_word_end(-argument)
+        self.selection_mark = -1
+        for x in range(argument):
+            self.point = NextWordEnd
+
+######### Movement select
+    def beginning_of_line_extend_selection(self):
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        self.point = StartOfLine
+        
+    def end_of_line_extend_selection(self):
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        self.point = EndOfLine
+
+    def forward_char_extend_selection(self,argument=1):
+        if argument < 0:
+            self.backward_char_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = NextChar
+        
+    def backward_char_extend_selection(self, argument=1):
+        if argument < 0:
+            self.forward_char_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = PrevChar
+        
+    def forward_word_extend_selection(self, argument=1):
+        if argument < 0:
+            self.backward_word_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = NextWordStart
+       
+    def backward_word_extend_selection(self, argument=1):
+        if argument < 0:
+            self.forward_word_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = PrevWordStart
+
+       
+    def forward_word_end_extend_selection(self, argument=1):
+        if argument < 0:
+            self.backward_word_end_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = NextWordEnd
+
+    def backward_word_end_extend_selection(self, argument=1):
+        if argument < 0:
+            self.forward_word_end_extend_selection(-argument)
+        if self.enable_selection and self.selection_mark < 0:
+            self.selection_mark = self.point
+        for x in range(argument):
+            self.point = PrevWordEnd
+
+
+######### delete       
+
+    def delete_selection(self):
+        if self.enable_selection and self.selection_mark >= 0:
+            if self.selection_mark < self.point:
+                del self[self.selection_mark:self.point]
+                self.selection_mark = -1
+            else:                
+                del self[self.point:self.selection_mark]
+                self.selection_mark = -1
+            return True
+        else:
+            self.selection_mark = -1
+            return False
+
+    def delete_char(self, argument=1):
+        if argument < 0:
+            self.backward_delete_char(-argument)
+        if self.delete_selection():
+            argument -= 1
+        for x in range(argument):
+            del self[Point]
+        
+    def backward_delete_char(self, argument=1):
+        if argument < 0:
+            self.delete_char(-argument)
+        if self.delete_selection():
+            argument -= 1
+        for x in range(argument):
+            if self.point > 0:
+                self.backward_char()
+                self.delete_char()
+
+    def forward_delete_word(self, argument=1):
+        if argument < 0:
+            self.backward_delete_word(-argument)
+        if self.delete_selection():
+            argument -= 1
+        for x in range(argument):
+            del self[Point:NextWordStart]
+
+    def backward_delete_word(self, argument=1):
+        if argument < 0:
+            self.forward_delete_word(-argument)
+        if self.delete_selection():
+            argument -= 1
+        for x in range(argument):
+            del self[PrevWordStart:Point]
+
+    def delete_current_word(self):
+        if not self.delete_selection():
+            del self[CurrentWord]
+        self.selection_mark =- 1
+        
+    def delete_horizontal_space(self):
+        if self[Point] in " \t":
+            del self[PrevWordEnd:NextWordStart]
+        self.selection_mark = -1
+######### Case
+
+    def upcase_word(self):
+        p = self.point
+        try:
+            self[CurrentWord] = self[CurrentWord].upper()
+            self.point = p
+        except NotAWordError:
+            pass
+        
+    def downcase_word(self):
+        p = self.point
+        try:
+            self[CurrentWord] = self[CurrentWord].lower()
+            self.point = p
+        except NotAWordError:
+            pass
+        
+    def capitalize_word(self):
+        p = self.point
+        try:
+            self[CurrentWord] = self[CurrentWord].capitalize()
+            self.point = p
+        except NotAWordError:
+            pass
+########### Transpose
+    def transpose_chars(self):
+        p2 = Point(self)
+        if p2 == 0:
+            return
+        elif p2 == len(self):
+            p2 = p2 - 1
+        p1 = p2 - 1
+        self[p2], self[p1] = self[p1], self[p2]
+        self.point = p2 + 1
+
+    def transpose_words(self):
+        word1 = TextLine(self)
+        word2 = TextLine(self)
+        if self.point == len(self):
+            word2.point = PrevWordStart
+            word1.point = PrevWordStart(word2)
+        else:
+            word1.point = PrevWordStart
+            word2.point = NextWordStart
+        stop1 = NextWordEnd(word1)
+        stop2 = NextWordEnd(word2)
+        start1 = word1.point
+        start2 = word2.point
+        self[start2:stop2] = word1[Point:NextWordEnd]
+        self[start1:stop1] = word2[Point:NextWordEnd]
+        self.point = stop2
+        
+
+############ Kill
+
+    def kill_line(self):
+        self.add_to_kill_ring(self[self.point:])
+        del self.line_buffer[self.point:]
+    
+    def kill_whole_line(self):
+        self.add_to_kill_ring(self[:])
+        del self[:]
+    
+    def backward_kill_line(self):
+        del self[StartOfLine:Point]
+        
+    def unix_line_discard(self):
+        del self[StartOfLine:Point]
+        pass
+
+    def kill_word(self):
+        """Kills to next word ending"""
+        del self[Point:NextWordEnd]
+
+    def backward_kill_word(self):
+        """Kills to next word ending"""
+        if not self.delete_selection():
+            del self[PrevWordStart:Point]
+        self.selection_mark = -1
+
+    def forward_kill_word(self):
+        """Kills to next word ending"""
+        if not self.delete_selection():
+            del self[Point:NextWordEnd]
+        self.selection_mark = -1
+
+    def unix_word_rubout(self):
+        if not self.delete_selection():
+            del self[PrevSpace:Point]
+        self.selection_mark = -1
+
+    def kill_region(self):
+        pass
+
+    def copy_region_as_kill(self):
+        pass
+
+    def copy_backward_word(self):
+        pass
+
+    def copy_forward_word(self):
+        pass
+        
+
+    def yank(self):
+        self.paste_from_kill_ring()
+
+    def yank_pop(self):
+        pass
+
+##############  Mark 
+
+    def set_mark(self):
+        self.mark = self.point
+        
+    def exchange_point_and_mark(self):
+        pass
+
+
+    def copy_region_to_clipboard(self): # ()
+        '''Copy the text in the region to the windows clipboard.'''
+        if self.enable_win32_clipboard:
+                mark = min(self.mark, len(self.line_buffer))
+                cursor = min(self.point, len(self.line_buffer))
+                if self.mark == -1:
+                        return
+                begin = min(cursor, mark)
+                end = max(cursor, mark)
+                toclipboard = "".join(self.line_buffer[begin:end])
+                clipboard.SetClipboardText(toclipboard)
+
+    def copy_selection_to_clipboard(self): # ()
+        '''Copy the text in the region to the windows clipboard.'''
+        if self.enable_win32_clipboard and self.enable_selection and self.selection_mark >= 0:
+                selection_mark = min(self.selection_mark,len(self.line_buffer))
+                cursor = min(self.point,len(self.line_buffer))
+                if self.selection_mark == -1:
+                        return
+                begin = min(cursor, selection_mark)
+                end = max(cursor, selection_mark)
+                toclipboard = "".join(self.line_buffer[begin:end])
+                clipboard.SetClipboardText(toclipboard)
+
+
+    def cut_selection_to_clipboard(self): # ()
+        self.copy_selection_to_clipboard()
+        self.delete_selection()
+##############  Paste
+
+
+############## Kill ring
+    def add_to_kill_ring(self,txt):
+        self.kill_ring = [txt]
+        if kill_ring_to_clipboard:
+            clipboard.SetClipboardText(txt.get_line_text())
+
+
+    def paste_from_kill_ring(self):
+        if self.kill_ring:
+            self.insert_text(self.kill_ring[0])
+
+
+##################################################################
+q = ReadLineTextBuffer("asff asFArw  ewrWErhg", point=8)
+q = TextLine("asff asFArw  ewrWErhg", point=8)
+
+def show_pos(buff, pos, chr = "."):
+    l = len(buff.line_buffer)
+    def choice(bool):
+        if bool:
+            return chr
+        else:
+            return " "
+    return "".join([choice(pos==idx) for idx in range(l + 1)])
+
+
+def test_positioner(buff, points, positioner):
+    print((" %s "%positioner.__class__.__name__).center(40, "-"))
+    buffstr = buff.line_buffer
+    
+    print('"%s"'%(buffstr))
+    for point in points:
+        b = TextLine(buff, point = point)
+        out=[" "] * (len(buffstr) + 1)
+        pos = positioner(b)
+        if pos == point:
+            out[pos] = "&"
+        else:
+            out[point] = "."
+            out[pos] = "^"
+        print('"%s"'%("".join(out)))
+    
+if __name__ == "__main__":
+
+    print('%-15s "%s"'%("Position", q.get_line_text()))
+    print('%-15s "%s"'%("Point", show_pos(q, q.point)))
+
+
+    for name, positioner in all_positioners:
+        pos = positioner(q)
+        []
+        print('%-15s "%s"'%(name, show_pos(q, pos, "^")))
+
+    l = ReadLineTextBuffer("kjjk asads   asad")
+    l.point = EndOfLine
diff --git a/pyreadline/lineeditor/wordmatcher.py b/pyreadline/lineeditor/wordmatcher.py
new file mode 100644
index 0000000..1f84cf9
--- /dev/null
+++ b/pyreadline/lineeditor/wordmatcher.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import re, operator
+
+
+def str_find_all(str, ch):
+    result = []
+    index = 0
+    while index >= 0:
+        index = str.find(ch, index)
+        if index >= 0:
+            result.append(index)
+            index += 1
+    return result
+        
+
+word_pattern = re.compile("(x*)")
+
+def markwords(str, iswordfun):
+    markers = {True : "x", False : "o"}
+    return "".join([markers[iswordfun(ch)] for ch in str])
+
+def split_words(str, iswordfun):
+    return [x for x in word_pattern.split(markwords(str,iswordfun)) if x != ""]
+
+def mark_start_segment(str, is_segment):
+    def mark_start(s):
+        if s[0:1] == "x":
+            return "s" + s[1:]
+        else:
+            return s
+    return "".join(map(mark_start, split_words(str, is_segment)))
+
+def mark_end_segment(str, is_segment):
+    def mark_start(s):
+        if s[0:1] == "x":
+            return s[:-1] + "s"
+        else:
+            return s
+    return "".join(map(mark_start, split_words(str, is_segment)))
+    
+def mark_start_segment_index(str, is_segment):
+    return str_find_all(mark_start_segment(str, is_segment), "s")
+
+def mark_end_segment_index(str, is_segment):
+    return [x + 1 for x in str_find_all(mark_end_segment(str, is_segment), "s")]
+
+
+################  Following are used in lineobj  ###########################
+
+def is_word_token(str):
+    return not is_non_word_token(str)
+    
+def is_non_word_token(str):
+    if len(str) != 1 or str in " \t\n":
+        return True
+    else:
+        return False
+
+def next_start_segment(str, is_segment):
+    str = "".join(str)
+    result = []
+    for start in mark_start_segment_index(str, is_segment):
+        result[len(result):start] = [start for x in range(start - len(result))]
+    result[len(result):len(str)] = [len(str) for x in range(len(str) - len(result) + 1)]            
+    return result
+    
+def next_end_segment(str, is_segment):
+    str = "".join(str)
+    result = []
+    for start in mark_end_segment_index(str, is_segment):
+        result[len(result):start] = [start for x in range(start - len(result))]
+    result[len(result):len(str)] = [len(str) for x in range(len(str) - len(result) + 1)]            
+    return result    
+
+
+def prev_start_segment(str, is_segment):
+    str = "".join(str)
+    result = []
+    prev = 0
+    for start in mark_start_segment_index(str, is_segment):
+        result[len(result):start+1] = [prev for x in range(start - len(result) + 1)]
+        prev=start
+    result[len(result):len(str)] = [prev for x in range(len(str) - len(result) + 1)]            
+    return result
+
+def prev_end_segment(str, is_segment):
+    str = "".join(str)
+    result = []
+    prev = 0
+    for start in mark_end_segment_index(str, is_segment):
+        result[len(result):start + 1] = [prev for x in range(start - len(result) + 1)]
+        prev=start
+    result[len(result):len(str)] = [len(str) for x in range(len(str) - len(result) + 1)]            
+    return result    
+
diff --git a/pyreadline/logger.py b/pyreadline/logger.py
new file mode 100644
index 0000000..61e77f6
--- /dev/null
+++ b/pyreadline/logger.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import socket, logging, logging.handlers
+from pyreadline.unicode_helper import ensure_str
+
+host = "localhost"
+port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
+
+
+pyreadline_logger = logging.getLogger('PYREADLINE')
+pyreadline_logger.setLevel(logging.DEBUG)
+pyreadline_logger.propagate = False
+formatter = logging.Formatter('%(message)s')
+file_handler = None
+
+class NULLHandler(logging.Handler):
+    def emit(self, s):
+        pass
+
+class SocketStream(object):
+    def __init__(self, host, port):
+        self.logsocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
+
+    def write(self, s):
+        self.logsocket.sendto(ensure_str(s), (host, port))
+
+    def flush(self):
+        pass
+
+    def close(self):
+        pass
+
+socket_handler = None
+pyreadline_logger.addHandler(NULLHandler())
+
+def start_socket_log():
+    global socket_handler
+    socket_handler = logging.StreamHandler(SocketStream(host, port))
+    socket_handler.setFormatter(formatter)
+    pyreadline_logger.addHandler(socket_handler)
+
+def stop_socket_log():
+    global socket_handler
+    if socket_handler:
+        pyreadline_logger.removeHandler(socket_handler)
+        socket_handler = None
+
+def start_file_log(filename):
+    global file_handler
+    file_handler = logging.FileHandler(filename, "w")
+    pyreadline_logger.addHandler(file_handler)
+
+def stop_file_log():
+    global file_handler
+    if file_handler:
+        pyreadline_logger.removeHandler(file_handler)
+        file_handler.close()
+        file_handler = None
+
+def stop_logging():
+    log("STOPING LOG")
+    stop_file_log()
+    stop_socket_log()
+
+def log(s):
+    s = ensure_str(s)
+    pyreadline_logger.debug(s)
diff --git a/pyreadline/logserver.py b/pyreadline/logserver.py
new file mode 100644
index 0000000..e154086
--- /dev/null
+++ b/pyreadline/logserver.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import pickle
+import logging
+import logging.handlers
+import socketserver
+import struct,socket
+
+try:
+    import msvcrt
+except ImportError:
+    msvcrt = None
+    print("problem")
+
+
+port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
+host = 'localhost'
+
+def check_key():
+    if msvcrt is None:
+        return False
+    else:
+        if msvcrt.kbhit() != 0:
+            q = msvcrt.getch()
+            return q
+    return ""
+
+
+singleline=False
+
+def main():
+    print("Starting TCP logserver on port:", port)
+    print("Press q to quit logserver", port)
+    print("Press c to clear screen", port)
+    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+    s.bind(("", port))
+    s.settimeout(1)
+    while 1:
+        try:
+            data, addr = s.recvfrom(100000)
+            print(data, end=' ')
+        except socket.timeout:
+            key = check_key().lower()
+            if "q" == key:
+                print("Quitting logserver")
+                break
+            elif "c" == key:
+                print("\n" * 100)            
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/pyreadline/modes/__init__.py b/pyreadline/modes/__init__.py
new file mode 100644
index 0000000..c1078ae
--- /dev/null
+++ b/pyreadline/modes/__init__.py
@@ -0,0 +1,5 @@
+__all__=["emacs","notemacs","vi"]
+from . import emacs,notemacs,vi
+editingmodes=[emacs.EmacsMode,notemacs.NotEmacsMode,vi.ViMode]
+
+#add check to ensure all modes have unique mode names
\ No newline at end of file
diff --git a/pyreadline/modes/basemode.py b/pyreadline/modes/basemode.py
new file mode 100644
index 0000000..f91261a
--- /dev/null
+++ b/pyreadline/modes/basemode.py
@@ -0,0 +1,562 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import os,re,math,glob,sys,time
+import pyreadline.logger as logger
+from   pyreadline.logger import log
+from   pyreadline.keysyms.common import make_KeyPress_from_keydescr
+import pyreadline.lineeditor.lineobj as lineobj
+import pyreadline.lineeditor.history as history
+import pyreadline.clipboard as clipboard
+from pyreadline.error import ReadlineError,GetSetError
+from pyreadline.unicode_helper import ensure_str, ensure_unicode
+import collections
+in_ironpython="IronPython" in sys.version
+
+class BaseMode(object):
+    mode="base"
+    def __init__(self,rlobj):
+        self.argument=0
+        self.rlobj=rlobj
+        self.exit_dispatch = {}
+        self.key_dispatch = {}
+        self.argument=1
+        self.prevargument=None
+        self.l_buffer=lineobj.ReadLineTextBuffer("")
+        self._history=history.LineHistory()
+        self.completer_delims = " \t\n\"\\'`@$><=;|&{("
+        self.show_all_if_ambiguous = 'off'
+        self.mark_directories = 'on'
+        self.complete_filesystem = 'off'
+        self.completer = None
+        self.begidx = 0
+        self.endidx = 0
+        self.tabstop = 4
+        self.startup_hook = None
+        self.pre_input_hook = None
+        self.first_prompt = True
+        self.cursor_size=25
+        
+        self.prompt = ">>> "
+        
+        #Paste settings    
+        #assumes data on clipboard is path if shorter than 300 characters and doesn't contain \t or \n
+        #and replace \ with / for easier use in ipython
+        self.enable_ipython_paste_for_paths=True
+
+        #automatically convert tabseparated data to list of lists or array constructors
+        self.enable_ipython_paste_list_of_lists=True
+        self.enable_win32_clipboard=True
+
+        self.paste_line_buffer=[]
+
+        self._sub_modes=[]
+
+
+    def __repr__(self):
+        return "<BaseMode>"
+
+    def _gs(x):
+        def g(self):
+            return getattr(self.rlobj,x)
+        def s(self,q):
+            setattr(self.rlobj,x,q)
+        return g,s
+        
+    def _g(x):
+        def g(self):
+            return getattr(self.rlobj,x)
+        return g
+
+    def _argreset(self):
+        val=self.argument
+        self.argument=0
+        if val==0:
+            val=1
+        return val
+    argument_reset=property(_argreset)
+        
+#used in readline
+    ctrl_c_tap_time_interval=property(*_gs("ctrl_c_tap_time_interval"))
+    allow_ctrl_c=property(*_gs("allow_ctrl_c"))
+    _print_prompt=property(_g("_print_prompt"))
+    _update_line=property(_g("_update_line"))
+    console=property(_g("console"))
+    prompt_begin_pos=property(_g("prompt_begin_pos"))
+    prompt_end_pos=property(_g("prompt_end_pos"))
+
+#used in completer _completions
+#    completer_delims=property(*_gs("completer_delims"))
+    _bell=property(_g("_bell"))
+    bell_style=property(_g("bell_style"))
+
+#used in emacs
+    _clear_after=property(_g("_clear_after"))
+    _update_prompt_pos=property(_g("_update_prompt_pos"))
+
+#not used in basemode or emacs
+
+    def process_keyevent(self, keyinfo):
+        raise NotImplementedError
+
+    def readline_setup(self, prompt=''):
+        self.l_buffer.selection_mark=-1
+        if self.first_prompt:
+            self.first_prompt = False
+            if self.startup_hook:
+                try:
+                    self.startup_hook()
+                except:
+                    print('startup hook failed')
+                    traceback.print_exc()
+
+        self.l_buffer.reset_line()
+        self.prompt = prompt
+
+        if self.pre_input_hook:
+            try:
+                self.pre_input_hook()
+            except:
+                print('pre_input_hook failed')
+                traceback.print_exc()
+                self.pre_input_hook = None
+
+
+####################################
+
+
+    def finalize(self):
+        """Every bindable command should call this function for cleanup. 
+        Except those that want to set argument to a non-zero value.
+        """
+        self.argument = 0
+
+
+    def add_history(self, text):
+        self._history.add_history(lineobj.ReadLineTextBuffer(text))
+            
+
+    #Create key bindings:
+    def rl_settings_to_string(self):
+        out=["%-20s: %s"%("show all if ambigous",self.show_all_if_ambiguous)]
+        out.append("%-20s: %s"%("mark_directories",self.mark_directories))
+        out.append("%-20s: %s"%("bell_style",self.bell_style))
+        out.append("------------- key bindings ------------")
+        tablepat="%-7s %-7s %-7s %-15s %-15s "
+        out.append(tablepat%("Control","Meta","Shift","Keycode/char","Function"))
+        bindings=[(k[0],k[1],k[2],k[3],v.__name__) for k,v in self.key_dispatch.items()]
+        bindings.sort()
+        for key in bindings:
+            out.append(tablepat%(key))
+        return out
+    
+
+    def _bind_key(self, key, func):
+        """setup the mapping from key to call the function."""
+        if not isinstance(func, collections.Callable):
+            print("Trying to bind non method to keystroke:%s,%s"%(key,func))
+            raise ReadlineError("Trying to bind non method to keystroke:%s,%s,%s,%s"%(key,func,type(func),type(self._bind_key)))
+        keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple()
+        log(">>>%s -> %s<<<"%(keyinfo,func.__name__))
+        self.key_dispatch[keyinfo] = func
+
+    def _bind_exit_key(self, key):
+        """setup the mapping from key to call the function."""
+        keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple()
+        self.exit_dispatch[keyinfo] = None
+
+    def init_editing_mode(self, e): # (C-e)
+        """When in vi command mode, this causes a switch to emacs editing
+        mode."""
+
+        raise NotImplementedError
+#completion commands    
+    
+    def _get_completions(self):
+        """Return a list of possible completions for the string ending at the point.
+        Also set begidx and endidx in the process."""
+        completions = []
+        self.begidx = self.l_buffer.point
+        self.endidx = self.l_buffer.point
+        buf=self.l_buffer.line_buffer
+        if self.completer:
+            # get the string to complete
+            while self.begidx > 0:
+                self.begidx -= 1
+                if buf[self.begidx] in self.completer_delims:
+                    self.begidx += 1
+                    break
+            text = ensure_str(''.join(buf[self.begidx:self.endidx]))
+            log('complete text="%s"' % ensure_unicode(text))
+            i = 0
+            while 1:
+                try:
+                    r = self.completer(ensure_unicode(text), i)
+                except IndexError:
+                    break
+                i += 1
+                if r is None:
+                    break
+                elif r and r not in completions:
+                    completions.append(r)
+                else:
+                    pass
+            log('text completions=<%s>' % list(map(ensure_unicode, completions)))
+        if (self.complete_filesystem == "on") and not completions:
+            # get the filename to complete
+            while self.begidx > 0:
+                self.begidx -= 1
+                if buf[self.begidx] in ' \t\n':
+                    self.begidx += 1
+                    break
+            text = ensure_str(''.join(buf[self.begidx:self.endidx]))
+            log('file complete text="%s"' % ensure_unicode(text))
+            completions = list(map(ensure_unicode, glob.glob(os.path.expanduser(text) + '*'.encode('ascii'))))
+            if self.mark_directories == 'on':
+                mc = []
+                for f in completions:
+                    if os.path.isdir(f):
+                        mc.append(f + os.sep)
+                    else:
+                        mc.append(f)
+                completions = mc
+            log('fnames=<%s>' % list(map(ensure_unicode, completions)))
+        return completions
+
+
+    def _display_completions(self, completions):
+        if not completions:
+            return
+        self.console.write('\n')
+        wmax = max(list(map(len, completions)))
+        w, h = self.console.size()
+        cols = max(1, int((w-1) / (wmax+1)))
+        rows = int(math.ceil(float(len(completions)) / cols))
+        for row in range(rows):
+            s = ''
+            for col in range(cols):
+                i = col*rows + row
+                if i < len(completions):
+                    self.console.write(completions[i].ljust(wmax+1))
+            self.console.write('\n')
+        if in_ironpython:
+            self.prompt=sys.ps1
+        self._print_prompt()
+
+
+    def complete(self, e): # (TAB)
+        """Attempt to perform completion on the text before point. The
+        actual completion performed is application-specific. The default is
+        filename completion."""
+        completions = self._get_completions()
+        if completions:
+            cprefix = commonprefix(completions)
+            if len(cprefix) > 0:
+                rep = [ c for c in cprefix ]
+                point=self.l_buffer.point
+                self.l_buffer[self.begidx:self.endidx] = rep
+                self.l_buffer.point = point + len(rep) - (self.endidx - self.begidx)
+            if len(completions) > 1:
+                if self.show_all_if_ambiguous == 'on':
+                    self._display_completions(completions)
+                else:
+                    self._bell()
+        else:
+            self._bell()
+        self.finalize()
+
+    def possible_completions(self, e): # (M-?)
+        """List the possible completions of the text before point. """
+        completions = self._get_completions()
+        self._display_completions(completions)
+        self.finalize()
+
+    def insert_completions(self, e): # (M-*)
+        """Insert all completions of the text before point that would have
+        been generated by possible-completions."""
+        completions = self._get_completions()
+        b = self.begidx
+        e = self.endidx
+        for comp in completions:
+            rep = [ c for c in comp ]
+            rep.append(' ')
+            self.l_buffer[b:e] = rep
+            b += len(rep)
+            e = b
+        self.line_cursor = b    
+        self.finalize()
+
+    def menu_complete(self, e): # ()
+        """Similar to complete, but replaces the word to be completed with a
+        single match from the list of possible completions. Repeated
+        execution of menu-complete steps through the list of possible
+        completions, inserting each match in turn. At the end of the list of
+        completions, the bell is rung (subject to the setting of bell-style)
+        and the original text is restored. An argument of n moves n
+        positions forward in the list of matches; a negative argument may be
+        used to move backward through the list. This command is intended to
+        be bound to TAB, but is unbound by default."""
+        self.finalize()
+
+    ### Methods below here are bindable emacs functions
+
+
+    def insert_text(self, string):
+        """Insert text into the command line."""
+        self.l_buffer.insert_text(string, self.argument_reset)
+        self.finalize()
+
+    def beginning_of_line(self, e): # (C-a)
+        """Move to the start of the current line. """
+        self.l_buffer.beginning_of_line()
+        self.finalize()
+
+    def end_of_line(self, e): # (C-e)
+        """Move to the end of the line. """
+        self.l_buffer.end_of_line()
+        self.finalize()
+
+    def forward_char(self, e): # (C-f)
+        """Move forward a character. """
+        self.l_buffer.forward_char(self.argument_reset)
+        self.finalize()
+
+    def backward_char(self, e): # (C-b)
+        """Move back a character. """
+        self.l_buffer.backward_char(self.argument_reset)
+        self.finalize()
+
+    def forward_word(self, e): # (M-f)
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.forward_word(self.argument_reset)
+        self.finalize()
+
+    def backward_word(self, e): # (M-b)
+        """Move back to the start of the current or previous word. Words are
+        composed of letters and digits."""
+        self.l_buffer.backward_word(self.argument_reset)
+        self.finalize()
+
+    def forward_word_end(self, e): # ()
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.forward_word_end(self.argument_reset)
+        self.finalize()
+
+    def backward_word_end(self, e): # ()
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.backward_word_end(self.argument_reset)
+        self.finalize()
+
+### Movement with extend selection
+    def beginning_of_line_extend_selection(self, e): # 
+        """Move to the start of the current line. """
+        self.l_buffer.beginning_of_line_extend_selection()
+        self.finalize()
+
+    def end_of_line_extend_selection(self, e): # 
+        """Move to the end of the line. """
+        self.l_buffer.end_of_line_extend_selection()
+        self.finalize()
+
+    def forward_char_extend_selection(self, e): # 
+        """Move forward a character. """
+        self.l_buffer.forward_char_extend_selection(self.argument_reset)
+        self.finalize()
+
+    def backward_char_extend_selection(self, e): #
+        """Move back a character. """
+        self.l_buffer.backward_char_extend_selection(self.argument_reset)
+        self.finalize()
+
+    def forward_word_extend_selection(self, e): # 
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.forward_word_extend_selection(self.argument_reset)
+        self.finalize()
+
+    def backward_word_extend_selection(self, e): # 
+        """Move back to the start of the current or previous word. Words are
+        composed of letters and digits."""
+        self.l_buffer.backward_word_extend_selection(self.argument_reset)
+        self.finalize()
+
+    def forward_word_end_extend_selection(self, e): # 
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.forward_word_end_extend_selection(self.argument_reset)
+        self.finalize()
+
+    def backward_word_end_extend_selection(self, e): # 
+        """Move forward to the end of the next word. Words are composed of
+        letters and digits."""
+        self.l_buffer.forward_word_end_extend_selection(self.argument_reset)
+        self.finalize()
+
+
+######## Change case
+
+    def upcase_word(self, e): # (M-u)
+        """Uppercase the current (or following) word. With a negative
+        argument, uppercase the previous word, but do not move the cursor."""
+        self.l_buffer.upcase_word()
+        self.finalize()
+
+    def downcase_word(self, e): # (M-l)
+        """Lowercase the current (or following) word. With a negative
+        argument, lowercase the previous word, but do not move the cursor."""
+        self.l_buffer.downcase_word()
+        self.finalize()
+
+    def capitalize_word(self, e): # (M-c)
+        """Capitalize the current (or following) word. With a negative
+        argument, capitalize the previous word, but do not move the cursor."""
+        self.l_buffer.capitalize_word()
+        self.finalize()
+
+
+########
+    def clear_screen(self, e): # (C-l)
+        """Clear the screen and redraw the current line, leaving the current
+        line at the top of the screen."""
+        self.console.page()
+        self.finalize()
+
+    def redraw_current_line(self, e): # ()
+        """Refresh the current line. By default, this is unbound."""
+        self.finalize()
+
+    def accept_line(self, e): # (Newline or Return)
+        """Accept the line regardless of where the cursor is. If this line
+        is non-empty, it may be added to the history list for future recall
+        with add_history(). If this line is a modified history line, the
+        history line is restored to its original state."""
+        self.finalize()
+        return True
+
+    def delete_char(self, e): # (C-d)
+        """Delete the character at point. If point is at the beginning of
+        the line, there are no characters in the line, and the last
+        character typed was not bound to delete-char, then return EOF."""
+        self.l_buffer.delete_char(self.argument_reset)
+        self.finalize()
+
+    def backward_delete_char(self, e): # (Rubout)
+        """Delete the character behind the cursor. A numeric argument means
+        to kill the characters instead of deleting them."""
+        self.l_buffer.backward_delete_char(self.argument_reset)
+        self.finalize()
+
+    def backward_delete_word(self, e): # (Control-Rubout)
+        """Delete the character behind the cursor. A numeric argument means
+        to kill the characters instead of deleting them."""
+        self.l_buffer.backward_delete_word(self.argument_reset)
+        self.finalize()
+
+    def forward_delete_word(self, e): # (Control-Delete)
+        """Delete the character behind the cursor. A numeric argument means
+        to kill the characters instead of deleting them."""
+        self.l_buffer.forward_delete_word(self.argument_reset)
+        self.finalize()
+
+    def delete_horizontal_space(self, e): # ()
+        """Delete all spaces and tabs around point. By default, this is unbound. """
+        self.l_buffer.delete_horizontal_space()
+        self.finalize()
+
+    def self_insert(self, e): # (a, b, A, 1, !, ...)
+        """Insert yourself. """
+        if e.char and ord(e.char)!=0: #don't insert null character in buffer, can happen with dead keys.
+            self.insert_text(e.char)
+        self.finalize()
+
+
+#   Paste from clipboard
+
+    def paste(self,e):
+        """Paste windows clipboard.
+        Assume single line strip other lines and end of line markers and trailing spaces""" #(Control-v)
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(False)
+                txt=txt.split("\n")[0].strip("\r").strip("\n")
+                log("paste: >%s<"%list(map(ord,txt)))
+                self.insert_text(txt)
+        self.finalize()
+
+    def paste_mulitline_code(self,e):
+        """Paste windows clipboard as multiline code.
+        Removes any empty lines in the code"""
+        reg=re.compile("\r?\n")
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(False)
+                t=reg.split(txt)
+                t=[row for row in t if row.strip()!=""] #remove empty lines
+                if t!=[""]:
+                    self.insert_text(t[0])
+                    self.add_history(self.l_buffer.copy())
+                    self.paste_line_buffer=t[1:]
+                    log("multi: >%s<"%self.paste_line_buffer)
+                    return True
+                else:
+                    return False
+        self.finalize()
+        
+    def ipython_paste(self,e):
+        """Paste windows clipboard. If enable_ipython_paste_list_of_lists is 
+        True then try to convert tabseparated data to repr of list of lists or 
+        repr of array.
+        If enable_ipython_paste_for_paths==True then change \\ to / and spaces to \space"""
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(
+                                                self.enable_ipython_paste_list_of_lists)
+                if self.enable_ipython_paste_for_paths:
+                        if len(txt)<300 and ("\t" not in txt) and ("\n" not in txt):
+                                txt=txt.replace("\\","/").replace(" ",r"\ ")
+                self.insert_text(txt)
+        self.finalize()
+
+
+    def copy_region_to_clipboard(self, e): # ()
+        """Copy the text in the region to the windows clipboard."""
+        self.l_buffer.copy_region_to_clipboard()
+        self.finalize()
+
+    def copy_selection_to_clipboard(self, e): # ()
+        """Copy the text in the region to the windows clipboard."""
+        self.l_buffer.copy_selection_to_clipboard()
+        self.finalize()
+
+    def cut_selection_to_clipboard(self, e): # ()
+        """Copy the text in the region to the windows clipboard."""
+        self.l_buffer.cut_selection_to_clipboard()
+        self.finalize()
+
+    def dump_functions(self, e): # ()
+        """Print all of the functions and their key bindings to the Readline
+        output stream. If a numeric argument is supplied, the output is
+        formatted in such a way that it can be made part of an inputrc
+        file. This command is unbound by default."""
+        print()
+        txt="\n".join(self.rl_settings_to_string())
+        print(txt)
+        self._print_prompt()
+        self.finalize()
+
+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].lower() != item[:i+1].lower():
+                prefix = prefix[:i]
+                if i == 0: return ''
+                break
+    return prefix
diff --git a/pyreadline/modes/emacs.py b/pyreadline/modes/emacs.py
new file mode 100644
index 0000000..f007d2d
--- /dev/null
+++ b/pyreadline/modes/emacs.py
@@ -0,0 +1,730 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import os, sys, time
+import pyreadline.logger as logger
+from   pyreadline.logger import log
+from pyreadline.lineeditor.lineobj import Point
+import pyreadline.lineeditor.lineobj as lineobj
+import pyreadline.lineeditor.history as history
+from . import basemode
+from pyreadline.unicode_helper import ensure_unicode
+
+
+def format(keyinfo):
+    if len(keyinfo[-1]) != 1:
+        k = keyinfo + (-1,)
+    else:
+        k = keyinfo + (ord(keyinfo[-1]),)
+    return "(%s,%s,%s,%s,%x)"%k
+
+in_ironpython = "IronPython" in sys.version
+
+
+class IncrementalSearchPromptMode(object):
+    def __init__(self, rlobj):
+        pass
+
+    def _process_incremental_search_keyevent(self, keyinfo):
+        log("_process_incremental_search_keyevent")
+        keytuple = keyinfo.tuple()
+        #dispatch_func = self.key_dispatch.get(keytuple, default)
+        revtuples = []
+        fwdtuples = []
+        for ktuple, func in self.key_dispatch.items():
+            if func == self.reverse_search_history:
+                revtuples.append(ktuple)
+            elif func == self.forward_search_history:
+                fwdtuples.append(ktuple)
+        
+        
+        log("IncrementalSearchPromptMode %s %s"%(keyinfo, keytuple))
+        if keyinfo.keyname == 'backspace':
+            self.subsearch_query = self.subsearch_query[:-1]
+            if len(self.subsearch_query) > 0:
+                self.line = self.subsearch_fun(self.subsearch_query)
+            else:
+                self._bell()
+                self.line = ""   # empty query means no search result
+        elif keyinfo.keyname in ['return', 'escape']:
+            self._bell()
+            self.prompt = self.subsearch_oldprompt
+            self.process_keyevent_queue = self.process_keyevent_queue[:-1]
+            self._history.history_cursor = len(self._history.history)
+            if keyinfo.keyname == 'escape':
+                self.l_buffer.set_line(self.subsearch_old_line)
+            return True
+        elif keyinfo.keyname:
+            pass
+        elif keytuple in revtuples:
+            self.subsearch_fun = self._history.reverse_search_history
+            self.subsearch_prompt = "reverse-i-search%d`%s': "
+            self.line = self.subsearch_fun(self.subsearch_query)
+        elif keytuple in fwdtuples:
+            self.subsearch_fun = self._history.forward_search_history
+            self.subsearch_prompt = "forward-i-search%d`%s': "
+            self.line = self.subsearch_fun(self.subsearch_query)
+        elif keyinfo.control == False and keyinfo.meta == False:
+            self.subsearch_query += keyinfo.char
+            self.line = self.subsearch_fun(self.subsearch_query)
+        else:
+            pass
+        self.prompt = self.subsearch_prompt%(self._history.history_cursor, self.subsearch_query)
+        self.l_buffer.set_line(self.line)
+
+    def _init_incremental_search(self, searchfun, init_event):
+        """Initialize search prompt
+        """
+        log("init_incremental_search")
+        self.subsearch_query = ''
+        self.subsearch_fun = searchfun
+        self.subsearch_old_line = self.l_buffer.get_line_text()
+
+        queue = self.process_keyevent_queue
+        queue.append(self._process_incremental_search_keyevent)
+
+        self.subsearch_oldprompt = self.prompt
+
+        if (self.previous_func != self.reverse_search_history and
+            self.previous_func != self.forward_search_history):
+            self.subsearch_query = self.l_buffer[0:Point].get_line_text()
+
+        if self.subsearch_fun == self.reverse_search_history:
+            self.subsearch_prompt = "reverse-i-search%d`%s': "
+        else:
+            self.subsearch_prompt = "forward-i-search%d`%s': "
+
+        self.prompt = self.subsearch_prompt%(self._history.history_cursor, "")
+
+        if self.subsearch_query:
+            self.line = self._process_incremental_search_keyevent(init_event)
+        else:
+            self.line = ""
+
+
+class SearchPromptMode(object):
+    def __init__(self, rlobj):
+        pass
+
+    def _process_non_incremental_search_keyevent(self, keyinfo):
+        keytuple = keyinfo.tuple()
+        log("SearchPromptMode %s %s"%(keyinfo, keytuple))
+        history = self._history
+
+        if keyinfo.keyname == 'backspace':
+            self.non_inc_query = self.non_inc_query[:-1]
+        elif keyinfo.keyname in ['return', 'escape']:
+            if self.non_inc_query:
+                if self.non_inc_direction == -1:
+                    res = history.reverse_search_history(self.non_inc_query)
+                else:
+                    res = history.forward_search_history(self.non_inc_query)
+
+            self._bell()
+            self.prompt = self.non_inc_oldprompt
+            self.process_keyevent_queue = self.process_keyevent_queue[:-1]
+            self._history.history_cursor = len(self._history.history)
+            if keyinfo.keyname == 'escape':
+                self.l_buffer = self.non_inc_oldline
+            else:
+                self.l_buffer.set_line(res)
+            return False
+        elif keyinfo.keyname:
+            pass
+        elif keyinfo.control == False and keyinfo.meta == False:
+            self.non_inc_query += keyinfo.char
+        else:
+            pass
+        self.prompt = self.non_inc_oldprompt + ":" + self.non_inc_query
+
+    def _init_non_i_search(self, direction):
+        self.non_inc_direction = direction
+        self.non_inc_query = ""
+        self.non_inc_oldprompt = self.prompt
+        self.non_inc_oldline = self.l_buffer.copy()
+        self.l_buffer.reset_line()
+        self.prompt = self.non_inc_oldprompt + ":"
+        queue = self.process_keyevent_queue
+        queue.append(self._process_non_incremental_search_keyevent)
+
+    def non_incremental_reverse_search_history(self, e):  # (M-p)
+        '''Search backward starting at the current line and moving up
+        through the history as necessary using a non-incremental search for
+        a string supplied by the user.'''
+        return self._init_non_i_search(-1)
+
+    def non_incremental_forward_search_history(self, e):  # (M-n)
+        '''Search forward starting at the current line and moving down
+        through the the history as necessary using a non-incremental search
+        for a string supplied by the user.'''
+        return self._init_non_i_search(1)
+
+
+class LeaveModeTryNext(Exception):
+    pass
+
+
+class DigitArgumentMode(object):
+    def __init__(self, rlobj):
+        pass
+
+    def _process_digit_argument_keyevent(self, keyinfo):
+        log("DigitArgumentMode.keyinfo %s"%keyinfo)
+        keytuple = keyinfo.tuple()
+        log("DigitArgumentMode.keytuple %s %s"%(keyinfo, keytuple))
+        if keyinfo.keyname in ['return']:
+            self.prompt = self._digit_argument_oldprompt
+            self.process_keyevent_queue = self.process_keyevent_queue[:-1]
+            return True
+        elif keyinfo.keyname:
+            pass
+        elif (keyinfo.char in "0123456789" and
+              keyinfo.control == False and
+              keyinfo.meta == False):
+            log("arg %s %s"%(self.argument, keyinfo.char))
+            self.argument = self.argument * 10 + int(keyinfo.char)
+        else:
+            self.prompt = self._digit_argument_oldprompt
+            raise LeaveModeTryNext
+        self.prompt = "(arg: %s) "%self.argument
+
+    def _init_digit_argument(self, keyinfo):
+        """Initialize search prompt
+        """
+        c = self.console
+        line = self.l_buffer.get_line_text()
+        self._digit_argument_oldprompt = self.prompt
+        queue = self.process_keyevent_queue
+        queue = self.process_keyevent_queue
+        queue.append(self._process_digit_argument_keyevent)
+
+        if keyinfo.char == "-":
+            self.argument = -1
+        elif keyinfo.char in "0123456789":
+            self.argument = int(keyinfo.char)
+        log("<%s> %s"%(self.argument, type(self.argument)))
+        self.prompt = "(arg: %s) "%self.argument
+        log("arg-init %s %s"%(self.argument, keyinfo.char))
+
+
+class EmacsMode(DigitArgumentMode, IncrementalSearchPromptMode,
+                SearchPromptMode, basemode.BaseMode):
+    mode = "emacs"
+
+    def __init__(self, rlobj):
+        basemode.BaseMode.__init__(self, rlobj)
+        IncrementalSearchPromptMode.__init__(self, rlobj)
+        SearchPromptMode.__init__(self, rlobj)
+        DigitArgumentMode.__init__(self, rlobj)
+        self._keylog = (lambda x, y: None)
+        self.previous_func = None
+        self.prompt = ">>> "
+        self._insert_verbatim = False
+        self.next_meta = False  # True to force meta on next character
+
+        self.process_keyevent_queue = [self._process_keyevent]
+
+    def __repr__(self):
+        return "<EmacsMode>"
+
+    def add_key_logger(self, logfun):
+        """logfun should be function that takes disp_fun and line_"""\
+        """buffer object """
+        self._keylog = logfun
+
+    def process_keyevent(self, keyinfo):
+        try:
+            r = self.process_keyevent_queue[-1](keyinfo)
+        except LeaveModeTryNext:
+            self.process_keyevent_queue = self.process_keyevent_queue[:-1]
+            r = self.process_keyevent(keyinfo)
+        if r:
+            self.add_history(self.l_buffer.copy())
+            return True
+        return False
+
+    def _process_keyevent(self, keyinfo):
+        """return True when line is final
+        """
+        #Process exit keys. Only exit on empty line
+        log("_process_keyevent <%s>"%keyinfo)
+
+        def nop(e):
+            pass
+        if self.next_meta:
+            self.next_meta = False
+            keyinfo.meta = True
+        keytuple = keyinfo.tuple()
+
+        if self._insert_verbatim:
+            self.insert_text(keyinfo)
+            self._insert_verbatim = False
+            self.argument = 0
+            return False
+
+        if keytuple in self.exit_dispatch:
+            pars = (self.l_buffer, lineobj.EndOfLine(self.l_buffer))
+            log("exit_dispatch:<%s, %s>"%pars)
+            if lineobj.EndOfLine(self.l_buffer) == 0:
+                raise EOFError
+        if keyinfo.keyname or keyinfo.control or keyinfo.meta:
+            default = nop
+        else:
+            default = self.self_insert
+        dispatch_func = self.key_dispatch.get(keytuple, default)
+
+        log("readline from keyboard:<%s,%s>"%(keytuple, dispatch_func))
+
+        r = None
+        if dispatch_func:
+            r = dispatch_func(keyinfo)
+            self._keylog(dispatch_func, self.l_buffer)
+            self.l_buffer.push_undo()
+
+        self.previous_func = dispatch_func
+        return r
+
+#########  History commands
+    def previous_history(self, e):  # (C-p)
+        '''Move back through the history list, fetching the previous
+        command. '''
+        self._history.previous_history(self.l_buffer)
+        self.l_buffer.point = lineobj.EndOfLine
+        self.finalize()
+
+    def next_history(self, e):  # (C-n)
+        '''Move forward through the history list, fetching the next
+        command. '''
+        self._history.next_history(self.l_buffer)
+        self.finalize()
+
+    def beginning_of_history(self, e):  # (M-<)
+        '''Move to the first line in the history.'''
+        self._history.beginning_of_history()
+        self.finalize()
+
+    def end_of_history(self, e):  # (M->)
+        '''Move to the end of the input history, i.e., the line currently
+        being entered.'''
+        self._history.end_of_history(self.l_buffer)
+        self.finalize()
+
+    def reverse_search_history(self, e):  # (C-r)
+        '''Search backward starting at the current line and moving up
+        through the history as necessary. This is an incremental search.'''
+        log("rev_search_history")
+        self._init_incremental_search(self._history.reverse_search_history, e)
+        self.finalize()
+
+    def forward_search_history(self, e):  # (C-s)
+        '''Search forward starting at the current line and moving down
+        through the the history as necessary. This is an incremental
+        search.'''
+        log("fwd_search_history")
+        self._init_incremental_search(self._history.forward_search_history, e)
+        self.finalize()
+
+    def history_search_forward(self, e):  # ()
+        '''Search forward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        if (self.previous_func and
+            hasattr(self._history, self.previous_func.__name__)):
+            self._history.lastcommand = getattr(self._history,
+                                                self.previous_func.__name__)
+        else:
+            self._history.lastcommand = None
+        q = self._history.history_search_forward(self.l_buffer)
+        self.l_buffer = q
+        self.l_buffer.point = q.point
+        self.finalize()
+
+    def history_search_backward(self, e):  # ()
+        '''Search backward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        if (self.previous_func and
+            hasattr(self._history, self.previous_func.__name__)):
+            self._history.lastcommand = getattr(self._history,
+                                                self.previous_func.__name__)
+        else:
+            self._history.lastcommand = None
+        q = self._history.history_search_backward(self.l_buffer)
+        self.l_buffer = q
+        self.l_buffer.point = q.point
+        self.finalize()
+
+    def yank_nth_arg(self, e):  # (M-C-y)
+        '''Insert the first argument to the previous command (usually the
+        second word on the previous line) at point. With an argument n,
+        insert the nth word from the previous command (the words in the
+        previous command begin with word 0). A negative argument inserts the
+        nth word from the end of the previous command.'''
+        self.finalize()
+
+    def yank_last_arg(self, e):  # (M-. or M-_)
+        '''Insert last argument to the previous command (the last word of
+        the previous history entry). With an argument, behave exactly like
+        yank-nth-arg. Successive calls to yank-last-arg move back through
+        the history list, inserting the last argument of each line in turn.'''
+        self.finalize()
+
+    def forward_backward_delete_char(self, e):  # ()
+        '''Delete the character under the cursor, unless the cursor is at
+        the end of the line, in which case the character behind the cursor
+        is deleted. By default, this is not bound to a key.'''
+        self.finalize()
+
+    def quoted_insert(self, e):  # (C-q or C-v)
+        '''Add the next character typed to the line verbatim. This is how to
+        insert key sequences like C-q, for example.'''
+        self._insert_verbatim = True
+        self.finalize()
+
+    def tab_insert(self, e):  # (M-TAB)
+        '''Insert a tab character. '''
+        cursor = min(self.l_buffer.point, len(self.l_buffer.line_buffer))
+        ws = ' ' * (self.tabstop - (cursor % self.tabstop))
+        self.insert_text(ws)
+        self.finalize()
+
+    def transpose_chars(self, e):  # (C-t)
+        '''Drag the character before the cursor forward over the character
+        at the cursor, moving the cursor forward as well. If the insertion
+        point is at the end of the line, then this transposes the last two
+        characters of the line. Negative arguments have no effect.'''
+        self.l_buffer.transpose_chars()
+        self.finalize()
+
+    def transpose_words(self, e):  # (M-t)
+        '''Drag the word before point past the word after point, moving
+        point past that word as well. If the insertion point is at the end
+        of the line, this transposes the last two words on the line.'''
+        self.l_buffer.transpose_words()
+        self.finalize()
+
+    def overwrite_mode(self, e):  # ()
+        '''Toggle overwrite mode. With an explicit positive numeric
+        argument, switches to overwrite mode. With an explicit non-positive
+        numeric argument, switches to insert mode. This command affects only
+        emacs mode; vi mode does overwrite differently. Each call to
+        readline() starts in insert mode. In overwrite mode, characters
+        bound to self-insert replace the text at point rather than pushing
+        the text to the right. Characters bound to backward-delete-char
+        replace the character before point with a space.'''
+        self.finalize()
+
+    def kill_line(self, e):  # (C-k)
+        '''Kill the text from point to the end of the line. '''
+        self.l_buffer.kill_line()
+        self.finalize()
+
+    def backward_kill_line(self, e):  # (C-x Rubout)
+        '''Kill backward to the beginning of the line. '''
+        self.l_buffer.backward_kill_line()
+        self.finalize()
+
+    def unix_line_discard(self, e):  # (C-u)
+        '''Kill backward from the cursor to the beginning of the current
+        line. '''
+        # how is this different from backward_kill_line?
+        self.l_buffer.unix_line_discard()
+        self.finalize()
+
+    def kill_whole_line(self, e):  # ()
+        '''Kill all characters on the current line, no matter where point
+        is. By default, this is unbound.'''
+        self.l_buffer.kill_whole_line()
+        self.finalize()
+
+    def kill_word(self, e):  # (M-d)
+        '''Kill from point to the end of the current word, or if between
+        words, to the end of the next word. Word boundaries are the same as
+        forward-word.'''
+        self.l_buffer.kill_word()
+        self.finalize()
+
+    forward_kill_word = kill_word
+
+    def backward_kill_word(self, e):  # (M-DEL)
+        '''Kill the word behind point. Word boundaries are the same as
+        backward-word. '''
+        self.l_buffer.backward_kill_word()
+        self.finalize()
+
+    def unix_word_rubout(self, e):  # (C-w)
+        '''Kill the word behind point, using white space as a word
+        boundary. The killed text is saved on the kill-ring.'''
+        self.l_buffer.unix_word_rubout()
+        self.finalize()
+
+    def kill_region(self, e):  # ()
+        '''Kill the text in the current region. By default, this command is
+        unbound. '''
+        self.finalize()
+
+    def copy_region_as_kill(self, e):  # ()
+        '''Copy the text in the region to the kill buffer, so it can be
+        yanked right away. By default, this command is unbound.'''
+        self.finalize()
+
+    def copy_backward_word(self, e):  # ()
+        '''Copy the word before point to the kill buffer. The word
+        boundaries are the same as backward-word. By default, this command
+        is unbound.'''
+        self.finalize()
+
+    def copy_forward_word(self, e):  # ()
+        '''Copy the word following point to the kill buffer. The word
+        boundaries are the same as forward-word. By default, this command is
+        unbound.'''
+        self.finalize()
+
+    def yank(self, e):  # (C-y)
+        '''Yank the top of the kill ring into the buffer at point. '''
+        self.l_buffer.yank()
+        self.finalize()
+
+    def yank_pop(self, e):  # (M-y)
+        '''Rotate the kill-ring, and yank the new top. You can only do this
+        if the prior command is yank or yank-pop.'''
+        self.l_buffer.yank_pop()
+        self.finalize()
+
+    def delete_char_or_list(self, e):  # ()
+        '''Deletes the character under the cursor if not at the beginning or
+        end of the line (like delete-char). If at the end of the line,
+        behaves identically to possible-completions. This command is unbound
+        by default.'''
+        self.finalize()
+
+    def start_kbd_macro(self, e):  # (C-x ()
+        '''Begin saving the characters typed into the current keyboard
+        macro. '''
+        self.finalize()
+
+    def end_kbd_macro(self, e):  # (C-x ))
+        '''Stop saving the characters typed into the current keyboard macro
+        and save the definition.'''
+        self.finalize()
+
+    def call_last_kbd_macro(self, e):  # (C-x e)
+        '''Re-execute the last keyboard macro defined, by making the
+        characters in the macro appear as if typed at the keyboard.'''
+        self.finalize()
+
+    def re_read_init_file(self, e):  # (C-x C-r)
+        '''Read in the contents of the inputrc file, and incorporate any
+        bindings or variable assignments found there.'''
+        self.finalize()
+
+    def abort(self, e):  # (C-g)
+        '''Abort the current editing command and ring the terminals bell
+             (subject to the setting of bell-style).'''
+        self._bell()
+        self.finalize()
+
+    def do_uppercase_version(self, e):  # (M-a, M-b, M-x, ...)
+        '''If the metafied character x is lowercase, run the command that is
+        bound to the corresponding uppercase character.'''
+        self.finalize()
+
+    def prefix_meta(self, e):  # (ESC)
+        '''Metafy the next character typed. This is for keyboards without a
+        meta key. Typing ESC f is equivalent to typing M-f. '''
+        self.next_meta = True
+        self.finalize()
+
+    def undo(self, e):  # (C-_ or C-x C-u)
+        '''Incremental undo, separately remembered for each line.'''
+        self.l_buffer.pop_undo()
+        self.finalize()
+
+    def revert_line(self, e):  # (M-r)
+        '''Undo all changes made to this line. This is like executing the
+        undo command enough times to get back to the beginning.'''
+        self.finalize()
+
+    def tilde_expand(self, e):  # (M-~)
+        '''Perform tilde expansion on the current word.'''
+        self.finalize()
+
+    def set_mark(self, e):  # (C-@)
+        '''Set the mark to the point. If a numeric argument is supplied, the
+        mark is set to that position.'''
+        self.l_buffer.set_mark()
+        self.finalize()
+
+    def exchange_point_and_mark(self, e):  # (C-x C-x)
+        '''Swap the point with the mark. The current cursor position is set
+        to the saved position, and the old cursor position is saved as the
+        mark.'''
+        self.finalize()
+
+    def character_search(self, e):  # (C-])
+        '''A character is read and point is moved to the next occurrence of
+        that character. A negative count searches for previous occurrences.'''
+        self.finalize()
+
+    def character_search_backward(self, e):  # (M-C-])
+        '''A character is read and point is moved to the previous occurrence
+        of that character. A negative count searches for subsequent
+        occurrences.'''
+        self.finalize()
+
+    def insert_comment(self, e):  # (M-#)
+        '''Without a numeric argument, the value of the comment-begin
+        variable is inserted at the beginning of the current line. If a
+        numeric argument is supplied, this command acts as a toggle: if the
+        characters at the beginning of the line do not match the value of
+        comment-begin, the value is inserted, otherwise the characters in
+        comment-begin are deleted from the beginning of the line. In either
+        case, the line is accepted as if a newline had been typed.'''
+        self.finalize()
+
+    def dump_variables(self, e):  # ()
+        '''Print all of the settable variables and their values to the
+        Readline output stream. If a numeric argument is supplied, the
+        output is formatted in such a way that it can be made part of an
+        inputrc file. This command is unbound by default.'''
+        self.finalize()
+
+    def dump_macros(self, e):  # ()
+        '''Print all of the Readline key sequences bound to macros and the
+        strings they output. If a numeric argument is supplied, the output
+        is formatted in such a way that it can be made part of an inputrc
+        file. This command is unbound by default.'''
+        self.finalize()
+
+    def digit_argument(self, e):  # (M-0, M-1, ... M--)
+        '''Add this digit to the argument already accumulating, or start a
+        new argument. M-- starts a negative argument.'''
+        self._init_digit_argument(e)
+        #Should not finalize
+
+    def universal_argument(self, e):  # ()
+        '''This is another way to specify an argument. If this command is
+        followed by one or more digits, optionally with a leading minus
+        sign, those digits define the argument. If the command is followed
+        by digits, executing universal-argument again ends the numeric
+        argument, but is otherwise ignored. As a special case, if this
+        command is immediately followed by a character that is neither a
+        digit or minus sign, the argument count for the next command is
+        multiplied by four. The argument count is initially one, so
+        executing this function the first time makes the argument count
+        four, a second time makes the argument count sixteen, and so on. By
+        default, this is not bound to a key.'''
+        #Should not finalize
+
+    #Create key bindings:
+    def init_editing_mode(self, e):  # (C-e)
+        '''When in vi command mode, this causes a switch to emacs editing
+        mode.'''
+        self._bind_exit_key('Control-d')
+        self._bind_exit_key('Control-z')
+
+        # I often accidentally hold the shift or control while typing space
+        self._bind_key('space',       self.self_insert)
+        self._bind_key('Shift-space',       self.self_insert)
+        self._bind_key('Control-space',     self.self_insert)
+        self._bind_key('Return',            self.accept_line)
+        self._bind_key('Left',              self.backward_char)
+        self._bind_key('Control-b',         self.backward_char)
+        self._bind_key('Right',             self.forward_char)
+        self._bind_key('Control-f',         self.forward_char)
+        self._bind_key('Control-h',         self.backward_delete_char)
+        self._bind_key('BackSpace',         self.backward_delete_char)
+        self._bind_key('Control-BackSpace', self.backward_delete_word)
+
+        self._bind_key('Home',              self.beginning_of_line)
+        self._bind_key('End',               self.end_of_line)
+        self._bind_key('Delete',            self.delete_char)
+        self._bind_key('Control-d',         self.delete_char)
+        self._bind_key('Clear',             self.clear_screen)
+        self._bind_key('Alt-f',             self.forward_word)
+        self._bind_key('Alt-b',             self.backward_word)
+        self._bind_key('Control-l',         self.clear_screen)
+        self._bind_key('Control-p',         self.previous_history)
+        self._bind_key('Up',                self.history_search_backward)
+        self._bind_key('Control-n',         self.next_history)
+        self._bind_key('Down',              self.history_search_forward)
+        self._bind_key('Control-a',         self.beginning_of_line)
+        self._bind_key('Control-e',         self.end_of_line)
+        self._bind_key('Alt-<',             self.beginning_of_history)
+        self._bind_key('Alt->',             self.end_of_history)
+        self._bind_key('Control-r',         self.reverse_search_history)
+        self._bind_key('Control-s',         self.forward_search_history)
+        self._bind_key('Control-Shift-r',         self.forward_search_history)
+        self._bind_key('Alt-p',
+                       self.non_incremental_reverse_search_history)
+        self._bind_key('Alt-n',
+                       self.non_incremental_forward_search_history)
+        self._bind_key('Control-z',         self.undo)
+        self._bind_key('Control-_',         self.undo)
+        self._bind_key('Escape',            self.kill_whole_line)
+        self._bind_key('Meta-d',            self.kill_word)
+        self._bind_key('Control-Delete',       self.forward_delete_word)
+        self._bind_key('Control-w',         self.unix_word_rubout)
+        #self._bind_key('Control-Shift-v',   self.quoted_insert)
+        self._bind_key('Control-v',         self.paste)
+        self._bind_key('Alt-v',             self.ipython_paste)
+        self._bind_key('Control-y',         self.yank)
+        self._bind_key('Control-k',         self.kill_line)
+        self._bind_key('Control-m',         self.set_mark)
+        self._bind_key('Control-q',         self.copy_region_to_clipboard)
+#        self._bind_key('Control-shift-k',  self.kill_whole_line)
+        self._bind_key('Control-Shift-v',   self.paste_mulitline_code)
+        self._bind_key("Control-Right",     self.forward_word_end)
+        self._bind_key("Control-Left",      self.backward_word)
+        self._bind_key("Shift-Right",
+                       self.forward_char_extend_selection)
+        self._bind_key("Shift-Left",
+                       self.backward_char_extend_selection)
+        self._bind_key("Shift-Control-Right",
+                       self.forward_word_end_extend_selection)
+        self._bind_key("Shift-Control-Left",
+                       self.backward_word_extend_selection)
+        self._bind_key("Shift-Home",
+                       self.beginning_of_line_extend_selection)
+        self._bind_key("Shift-End",
+                       self.end_of_line_extend_selection)
+        self._bind_key("numpad0",           self.self_insert)
+        self._bind_key("numpad1",           self.self_insert)
+        self._bind_key("numpad2",           self.self_insert)
+        self._bind_key("numpad3",           self.self_insert)
+        self._bind_key("numpad4",           self.self_insert)
+        self._bind_key("numpad5",           self.self_insert)
+        self._bind_key("numpad6",           self.self_insert)
+        self._bind_key("numpad7",           self.self_insert)
+        self._bind_key("numpad8",           self.self_insert)
+        self._bind_key("numpad9",           self.self_insert)
+        self._bind_key("add",               self.self_insert)
+        self._bind_key("subtract",          self.self_insert)
+        self._bind_key("multiply",          self.self_insert)
+        self._bind_key("divide",            self.self_insert)
+        self._bind_key("vk_decimal",        self.self_insert)
+        log("RUNNING INIT EMACS")
+        for i in range(0, 10):
+            self._bind_key("alt-%d"%i,      self.digit_argument)
+        self._bind_key("alt--",             self.digit_argument)
+
+
+# make it case insensitive
+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].lower() != item[:i + 1].lower():
+                prefix = prefix[:i]
+                if i == 0:
+                    return ''
+                break
+    return prefix
diff --git a/pyreadline/modes/notemacs.py b/pyreadline/modes/notemacs.py
new file mode 100644
index 0000000..c182a6d
--- /dev/null
+++ b/pyreadline/modes/notemacs.py
@@ -0,0 +1,602 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import os
+import pyreadline.logger as logger
+from   pyreadline.logger import log
+import pyreadline.lineeditor.lineobj as lineobj
+import pyreadline.lineeditor.history as history
+from . import basemode
+
+class NotEmacsMode(basemode.BaseMode):
+    mode="notemacs"
+    def __init__(self,rlobj):
+        super(NotEmacsMode,self).__init__(rlobj)
+
+    def __repr__(self):
+        return "<NotEmacsMode>"
+
+    def _readline_from_keyboard(self):
+        c=self.console
+        while 1:
+            self._update_line()
+            event = c.getkeypress()
+            if self.next_meta:
+                self.next_meta = False
+                control, meta, shift, code = event.keyinfo
+                event.keyinfo = (control, True, shift, code)
+
+            #Process exit keys. Only exit on empty line
+            if event.keyinfo in self.exit_dispatch:
+                if lineobj.EndOfLine(self.l_buffer) == 0:
+                    raise EOFError
+
+            dispatch_func = self.key_dispatch.get(event.keyinfo,self.self_insert)
+            log("readline from keyboard:%s"%(event.keyinfo,))
+            r = None
+            if dispatch_func:
+                r = dispatch_func(event)
+                self.l_buffer.push_undo()
+
+            self.previous_func = dispatch_func
+            if r:
+                self._update_line()
+                break
+
+    def readline(self, prompt=''):
+        '''Try to act like GNU readline.'''
+        # handle startup_hook
+        if self.first_prompt:
+            self.first_prompt = False
+            if self.startup_hook:
+                try:
+                    self.startup_hook()
+                except:
+                    print('startup hook failed')
+                    traceback.print_exc()
+
+        c = self.console
+        self.l_buffer.reset_line()
+        self.prompt = prompt
+        self._print_prompt()
+
+        if self.pre_input_hook:
+            try:
+                self.pre_input_hook()
+            except:
+                print('pre_input_hook failed')
+                traceback.print_exc()
+                self.pre_input_hook = None
+
+        log("in readline: %s"%self.paste_line_buffer)
+        if len(self.paste_line_buffer)>0:
+            self.l_buffer=lineobj.ReadlineTextBuffer(self.paste_line_buffer[0])
+            self._update_line()
+            self.paste_line_buffer=self.paste_line_buffer[1:]
+            c.write('\r\n')
+        else:
+            self._readline_from_keyboard()
+            c.write('\r\n')
+
+        self.add_history(self.l_buffer.copy())
+
+        log('returning(%s)' % self.l_buffer.get_line_text())
+        return self.l_buffer.get_line_text() + '\n'
+
+    ### Methods below here are bindable emacs functions
+
+    def beginning_of_line(self, e): # (C-a)
+        '''Move to the start of the current line. '''
+        self.l_buffer.beginning_of_line()
+
+    def end_of_line(self, e): # (C-e)
+        '''Move to the end of the line. '''
+        self.l_buffer.end_of_line()
+
+    def forward_char(self, e): # (C-f)
+        '''Move forward a character. '''
+        self.l_buffer.forward_char()
+
+    def backward_char(self, e): # (C-b)
+        '''Move back a character. '''
+        self.l_buffer.backward_char()
+
+    def forward_word(self, e): # (M-f)
+        '''Move forward to the end of the next word. Words are composed of
+        letters and digits.'''
+        self.l_buffer.forward_word()
+
+    def backward_word(self, e): # (M-b)
+        '''Move back to the start of the current or previous word. Words are
+        composed of letters and digits.'''
+        self.l_buffer.backward_word()
+
+    def clear_screen(self, e): # (C-l)
+        '''Clear the screen and redraw the current line, leaving the current
+        line at the top of the screen.'''
+        self.console.page()
+
+    def redraw_current_line(self, e): # ()
+        '''Refresh the current line. By default, this is unbound.'''
+        pass
+
+    def accept_line(self, e): # (Newline or Return)
+        '''Accept the line regardless of where the cursor is. If this line
+        is non-empty, it may be added to the history list for future recall
+        with add_history(). If this line is a modified history line, the
+        history line is restored to its original state.'''
+        return True
+
+#########  History commands
+    def previous_history(self, e): # (C-p)
+        '''Move back through the history list, fetching the previous command. '''
+        self._history.previous_history(self.l_buffer)
+
+    def next_history(self, e): # (C-n)
+        '''Move forward through the history list, fetching the next command. '''
+        self._history.next_history(self.l_buffer)
+
+    def beginning_of_history(self, e): # (M-<)
+        '''Move to the first line in the history.'''
+        self._history.beginning_of_history()
+
+    def end_of_history(self, e): # (M->)
+        '''Move to the end of the input history, i.e., the line currently
+        being entered.'''
+        self._history.end_of_history(self.l_buffer)
+
+    def _i_search(self, searchfun, direction, init_event):
+        c = self.console
+        line = self.get_line_buffer()
+        query = ''
+        hc_start = self._history.history_cursor #+ direction
+        while 1:
+            x, y = self.prompt_end_pos
+            c.pos(0, y)
+            if direction < 0:
+                prompt = 'reverse-i-search'
+            else:
+                prompt = 'forward-i-search'
+
+            scroll = c.write_scrolling("%s`%s': %s" % (prompt, query, line))
+            self._update_prompt_pos(scroll)
+            self._clear_after()
+
+            event = c.getkeypress()
+            if event.keysym == 'BackSpace':
+                if len(query) > 0:
+                    query = query[:-1]
+                    self._history.history_cursor = hc_start
+                else:
+                    self._bell()
+            elif event.char in string.letters + string.digits + string.punctuation + ' ':
+                self._history.history_cursor = hc_start
+                query += event.char
+            elif event.keyinfo == init_event.keyinfo:
+                self._history.history_cursor += direction
+                line=searchfun(query)                
+                pass
+            else:
+                if event.keysym != 'Return':
+                    self._bell()
+                break
+            line=searchfun(query)
+
+        px, py = self.prompt_begin_pos
+        c.pos(0, py)
+        self.l_buffer.set_line(line)
+        self._print_prompt()
+        self._history.history_cursor=len(self._history.history)
+
+    def reverse_search_history(self, e): # (C-r)
+        '''Search backward starting at the current line and moving up
+        through the history as necessary. This is an incremental search.'''
+#        print "HEJ"
+#        self.console.bell()
+        self._i_search(self._history.reverse_search_history, -1, e)
+
+    def forward_search_history(self, e): # (C-s)
+        '''Search forward starting at the current line and moving down
+        through the the history as necessary. This is an incremental search.'''
+#        print "HEJ"
+#        self.console.bell()
+        self._i_search(self._history.forward_search_history, 1, e)
+
+
+    def non_incremental_reverse_search_history(self, e): # (M-p)
+        '''Search backward starting at the current line and moving up
+        through the history as necessary using a non-incremental search for
+        a string supplied by the user.'''
+        self._history.non_incremental_reverse_search_history(self.l_buffer)
+
+    def non_incremental_forward_search_history(self, e): # (M-n)
+        '''Search forward starting at the current line and moving down
+        through the the history as necessary using a non-incremental search
+        for a string supplied by the user.'''
+        self._history.non_incremental_reverse_search_history(self.l_buffer)
+
+    def history_search_forward(self, e): # ()
+        '''Search forward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        self.l_buffer=self._history.history_search_forward(self.l_buffer)
+
+    def history_search_backward(self, e): # ()
+        '''Search backward through the history for the string of characters
+        between the start of the current line and the point. This is a
+        non-incremental search. By default, this command is unbound.'''
+        self.l_buffer=self._history.history_search_backward(self.l_buffer)
+
+    def yank_nth_arg(self, e): # (M-C-y)
+        '''Insert the first argument to the previous command (usually the
+        second word on the previous line) at point. With an argument n,
+        insert the nth word from the previous command (the words in the
+        previous command begin with word 0). A negative argument inserts the
+        nth word from the end of the previous command.'''
+        pass
+
+    def yank_last_arg(self, e): # (M-. or M-_)
+        '''Insert last argument to the previous command (the last word of
+        the previous history entry). With an argument, behave exactly like
+        yank-nth-arg. Successive calls to yank-last-arg move back through
+        the history list, inserting the last argument of each line in turn.'''
+        pass
+
+    def delete_char(self, e): # (C-d)
+        '''Delete the character at point. If point is at the beginning of
+        the line, there are no characters in the line, and the last
+        character typed was not bound to delete-char, then return EOF.'''
+        self.l_buffer.delete_char()
+
+    def backward_delete_char(self, e): # (Rubout)
+        '''Delete the character behind the cursor. A numeric argument means
+        to kill the characters instead of deleting them.'''
+        self.l_buffer.backward_delete_char()
+
+    def forward_backward_delete_char(self, e): # ()
+        '''Delete the character under the cursor, unless the cursor is at
+        the end of the line, in which case the character behind the cursor
+        is deleted. By default, this is not bound to a key.'''
+        pass
+
+    def quoted_insert(self, e): # (C-q or C-v)
+        '''Add the next character typed to the line verbatim. This is how to
+        insert key sequences like C-q, for example.'''
+        e = self.console.getkeypress()
+        self.insert_text(e.char)
+
+    def tab_insert(self, e): # (M-TAB)
+        '''Insert a tab character. '''
+        cursor = min(self.l_buffer.point, len(self.l_buffer.line_buffer))
+        ws = ' ' * (self.tabstop - (cursor % self.tabstop))
+        self.insert_text(ws)
+
+    def self_insert(self, e): # (a, b, A, 1, !, ...)
+        '''Insert yourself. '''
+        if ord(e.char)!=0: #don't insert null character in buffer, can happen with dead keys.
+            self.insert_text(e.char)
+
+    def transpose_chars(self, e): # (C-t)
+        '''Drag the character before the cursor forward over the character
+        at the cursor, moving the cursor forward as well. If the insertion
+        point is at the end of the line, then this transposes the last two
+        characters of the line. Negative arguments have no effect.'''
+        self.l_buffer.transpose_chars()
+
+    def transpose_words(self, e): # (M-t)
+        '''Drag the word before point past the word after point, moving
+        point past that word as well. If the insertion point is at the end
+        of the line, this transposes the last two words on the line.'''
+        self.l_buffer.transpose_words()
+
+    def upcase_word(self, e): # (M-u)
+        '''Uppercase the current (or following) word. With a negative
+        argument, uppercase the previous word, but do not move the cursor.'''
+        self.l_buffer.upcase_word()
+
+    def downcase_word(self, e): # (M-l)
+        '''Lowercase the current (or following) word. With a negative
+        argument, lowercase the previous word, but do not move the cursor.'''
+        self.l_buffer.downcase_word()
+
+    def capitalize_word(self, e): # (M-c)
+        '''Capitalize the current (or following) word. With a negative
+        argument, capitalize the previous word, but do not move the cursor.'''
+        self.l_buffer.capitalize_word()
+
+    def overwrite_mode(self, e): # ()
+        '''Toggle overwrite mode. With an explicit positive numeric
+        argument, switches to overwrite mode. With an explicit non-positive
+        numeric argument, switches to insert mode. This command affects only
+        emacs mode; vi mode does overwrite differently. Each call to
+        readline() starts in insert mode. In overwrite mode, characters
+        bound to self-insert replace the text at point rather than pushing
+        the text to the right. Characters bound to backward-delete-char
+        replace the character before point with a space.'''
+        pass
+        
+    def kill_line(self, e): # (C-k)
+        '''Kill the text from point to the end of the line. '''
+        self.l_buffer.kill_line()
+        
+    def backward_kill_line(self, e): # (C-x Rubout)
+        '''Kill backward to the beginning of the line. '''
+        self.l_buffer.backward_kill_line()
+
+    def unix_line_discard(self, e): # (C-u)
+        '''Kill backward from the cursor to the beginning of the current line. '''
+        # how is this different from backward_kill_line?
+        self.l_buffer.unix_line_discard()
+
+    def kill_whole_line(self, e): # ()
+        '''Kill all characters on the current line, no matter where point
+        is. By default, this is unbound.'''
+        self.l_buffer.kill_whole_line()
+
+    def kill_word(self, e): # (M-d)
+        '''Kill from point to the end of the current word, or if between
+        words, to the end of the next word. Word boundaries are the same as
+        forward-word.'''
+        self.l_buffer.kill_word()
+
+    def backward_kill_word(self, e): # (M-DEL)
+        '''Kill the word behind point. Word boundaries are the same as
+        backward-word. '''
+        self.l_buffer.backward_kill_word()
+
+    def unix_word_rubout(self, e): # (C-w)
+        '''Kill the word behind point, using white space as a word
+        boundary. The killed text is saved on the kill-ring.'''
+        self.l_buffer.unix_word_rubout()
+
+    def delete_horizontal_space(self, e): # ()
+        '''Delete all spaces and tabs around point. By default, this is unbound. '''
+        pass
+
+    def kill_region(self, e): # ()
+        '''Kill the text in the current region. By default, this command is unbound. '''
+        pass
+
+    def copy_region_as_kill(self, e): # ()
+        '''Copy the text in the region to the kill buffer, so it can be
+        yanked right away. By default, this command is unbound.'''
+        pass
+
+    def copy_region_to_clipboard(self, e): # ()
+        '''Copy the text in the region to the windows clipboard.'''
+        if self.enable_win32_clipboard:
+                mark=min(self.l_buffer.mark,len(self.l_buffer.line_buffer))
+                cursor=min(self.l_buffer.point,len(self.l_buffer.line_buffer))
+                if self.l_buffer.mark==-1:
+                        return
+                begin=min(cursor,mark)
+                end=max(cursor,mark)
+                toclipboard="".join(self.l_buffer.line_buffer[begin:end])
+                clipboard.SetClipboardText(str(toclipboard))
+
+    def copy_backward_word(self, e): # ()
+        '''Copy the word before point to the kill buffer. The word
+        boundaries are the same as backward-word. By default, this command
+        is unbound.'''
+        pass
+
+    def copy_forward_word(self, e): # ()
+        '''Copy the word following point to the kill buffer. The word
+        boundaries are the same as forward-word. By default, this command is
+        unbound.'''
+        pass
+
+    def paste(self,e):
+        '''Paste windows clipboard'''
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(False)
+                self.insert_text(txt)
+
+    def paste_mulitline_code(self,e):
+        '''Paste windows clipboard'''
+        reg=re.compile("\r?\n")
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(False)
+                t=reg.split(txt)
+                t=[row for row in t if row.strip()!=""] #remove empty lines
+                if t!=[""]:
+                    self.insert_text(t[0])
+                    self.add_history(self.l_buffer.copy())
+                    self.paste_line_buffer=t[1:]
+                    log("multi: %s"%self.paste_line_buffer)
+                    return True
+                else:
+                    return False
+        
+    def ipython_paste(self,e):
+        '''Paste windows clipboard. If enable_ipython_paste_list_of_lists is 
+        True then try to convert tabseparated data to repr of list of lists or 
+        repr of array'''
+        if self.enable_win32_clipboard:
+                txt=clipboard.get_clipboard_text_and_convert(
+                                                self.enable_ipython_paste_list_of_lists)
+                if self.enable_ipython_paste_for_paths:
+                        if len(txt)<300 and ("\t" not in txt) and ("\n" not in txt):
+                                txt=txt.replace("\\", "/").replace(" ", r"\ ")
+                self.insert_text(txt)
+
+    def yank(self, e): # (C-y)
+        '''Yank the top of the kill ring into the buffer at point. '''
+        pass
+
+    def yank_pop(self, e): # (M-y)
+        '''Rotate the kill-ring, and yank the new top. You can only do this
+        if the prior command is yank or yank-pop.'''
+        pass
+
+
+    def digit_argument(self, e): # (M-0, M-1, ... M--)
+        '''Add this digit to the argument already accumulating, or start a
+        new argument. M-- starts a negative argument.'''
+        pass
+
+    def universal_argument(self, e): # ()
+        '''This is another way to specify an argument. If this command is
+        followed by one or more digits, optionally with a leading minus
+        sign, those digits define the argument. If the command is followed
+        by digits, executing universal-argument again ends the numeric
+        argument, but is otherwise ignored. As a special case, if this
+        command is immediately followed by a character that is neither a
+        digit or minus sign, the argument count for the next command is
+        multiplied by four. The argument count is initially one, so
+        executing this function the first time makes the argument count
+        four, a second time makes the argument count sixteen, and so on. By
+        default, this is not bound to a key.'''
+        pass
+
+    def delete_char_or_list(self, e): # ()
+        '''Deletes the character under the cursor if not at the beginning or
+        end of the line (like delete-char). If at the end of the line,
+        behaves identically to possible-completions. This command is unbound
+        by default.'''
+        pass
+
+    def start_kbd_macro(self, e): # (C-x ()
+        '''Begin saving the characters typed into the current keyboard macro. '''
+        pass
+
+    def end_kbd_macro(self, e): # (C-x ))
+        '''Stop saving the characters typed into the current keyboard macro
+        and save the definition.'''
+        pass
+
+    def call_last_kbd_macro(self, e): # (C-x e)
+        '''Re-execute the last keyboard macro defined, by making the
+        characters in the macro appear as if typed at the keyboard.'''
+        pass
+
+    def re_read_init_file(self, e): # (C-x C-r)
+        '''Read in the contents of the inputrc file, and incorporate any
+        bindings or variable assignments found there.'''
+        pass
+
+    def abort(self, e): # (C-g)
+        '''Abort the current editing command and ring the terminals bell
+             (subject to the setting of bell-style).'''
+        self._bell()
+
+    def do_uppercase_version(self, e): # (M-a, M-b, M-x, ...)
+        '''If the metafied character x is lowercase, run the command that is
+        bound to the corresponding uppercase character.'''
+        pass
+
+    def prefix_meta(self, e): # (ESC)
+        '''Metafy the next character typed. This is for keyboards without a
+        meta key. Typing ESC f is equivalent to typing M-f. '''
+        self.next_meta = True
+
+    def undo(self, e): # (C-_ or C-x C-u)
+        '''Incremental undo, separately remembered for each line.'''
+        self.l_buffer.pop_undo()
+
+    def revert_line(self, e): # (M-r)
+        '''Undo all changes made to this line. This is like executing the
+        undo command enough times to get back to the beginning.'''
+        pass
+
+    def tilde_expand(self, e): # (M-~)
+        '''Perform tilde expansion on the current word.'''
+        pass
+
+    def set_mark(self, e): # (C-@)
+        '''Set the mark to the point. If a numeric argument is supplied, the
+        mark is set to that position.'''
+        self.l_buffer.set_mark()
+
+    def exchange_point_and_mark(self, e): # (C-x C-x)
+        '''Swap the point with the mark. The current cursor position is set
+        to the saved position, and the old cursor position is saved as the
+        mark.'''
+        pass
+
+    def character_search(self, e): # (C-])
+        '''A character is read and point is moved to the next occurrence of
+        that character. A negative count searches for previous occurrences.'''
+        pass
+
+    def character_search_backward(self, e): # (M-C-])
+        '''A character is read and point is moved to the previous occurrence
+        of that character. A negative count searches for subsequent
+        occurrences.'''
+        pass
+
+    def insert_comment(self, e): # (M-#)
+        '''Without a numeric argument, the value of the comment-begin
+        variable is inserted at the beginning of the current line. If a
+        numeric argument is supplied, this command acts as a toggle: if the
+        characters at the beginning of the line do not match the value of
+        comment-begin, the value is inserted, otherwise the characters in
+        comment-begin are deleted from the beginning of the line. In either
+        case, the line is accepted as if a newline had been typed.'''
+        pass
+
+    def dump_functions(self, e): # ()
+        '''Print all of the functions and their key bindings to the Readline
+        output stream. If a numeric argument is supplied, the output is
+        formatted in such a way that it can be made part of an inputrc
+        file. This command is unbound by default.'''
+        pass
+
+    def dump_variables(self, e): # ()
+        '''Print all of the settable variables and their values to the
+        Readline output stream. If a numeric argument is supplied, the
+        output is formatted in such a way that it can be made part of an
+        inputrc file. This command is unbound by default.'''
+        pass
+
+    def dump_macros(self, e): # ()
+        '''Print all of the Readline key sequences bound to macros and the
+        strings they output. If a numeric argument is supplied, the output
+        is formatted in such a way that it can be made part of an inputrc
+        file. This command is unbound by default.'''
+        pass
+
+
+    #Create key bindings:
+
+    def init_editing_mode(self, e): # (C-e)
+        '''When in vi command mode, this causes a switch to emacs editing
+        mode.'''
+
+        self._bind_exit_key('Control-d')
+        self._bind_exit_key('Control-z')
+
+        # I often accidentally hold the shift or control while typing space
+        self._bind_key('Shift-space',       self.self_insert)
+        self._bind_key('Control-space',     self.self_insert)
+        self._bind_key('Return',            self.accept_line)
+        self._bind_key('Left',              self.backward_char)
+        self._bind_key('Control-b',         self.backward_char)
+        self._bind_key('Right',             self.forward_char)
+        self._bind_key('Control-f',         self.forward_char)
+        self._bind_key('BackSpace',         self.backward_delete_char)
+        self._bind_key('Home',              self.beginning_of_line)
+        self._bind_key('End',               self.end_of_line)
+        self._bind_key('Delete',            self.delete_char)
+        self._bind_key('Control-d',         self.delete_char)
+        self._bind_key('Clear',             self.clear_screen)
+
+
+# make it case insensitive
+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].lower() != item[:i+1].lower():
+                prefix = prefix[:i]
+                if i == 0: return ''
+                break
+    return prefix
+
diff --git a/pyreadline/modes/vi.py b/pyreadline/modes/vi.py
new file mode 100644
index 0000000..8adedac
--- /dev/null
+++ b/pyreadline/modes/vi.py
@@ -0,0 +1,1174 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Michael Graz. <mgraz@plan10.com>
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import os
+import pyreadline.logger as logger
+from   pyreadline.logger import log
+import pyreadline.lineeditor.lineobj as lineobj
+import pyreadline.lineeditor.history as history
+from . import basemode
+
+class ViMode(basemode.BaseMode):
+    mode="vi"
+    def __init__(self,rlobj):
+        super(ViMode,self).__init__(rlobj)
+        self.__vi_insert_mode = None
+
+    def __repr__(self):
+        return "<ViMode>"
+
+    def process_keyevent(self, keyinfo):
+        def nop(e):
+            pass
+        keytuple=keyinfo.tuple()
+
+        #Process exit keys. Only exit on empty line
+        if keytuple in self.exit_dispatch:
+            if lineobj.EndOfLine(self.l_buffer) == 0:
+                raise EOFError
+
+        dispatch_func = self.key_dispatch.get(keytuple,self.vi_key)
+        log("readline from keyboard:%s->%s"%(keytuple,dispatch_func))
+        r = None
+        if dispatch_func:
+            r = dispatch_func(keyinfo)
+            self.l_buffer.push_undo()
+
+        self.previous_func = dispatch_func
+        if r:
+            self._update_line()
+            return True
+        return False
+        
+    ### Methods below here are bindable emacs functions
+
+    def init_editing_mode(self, e): # (M-C-j)
+        '''Initialize vi editingmode'''
+        self.show_all_if_ambiguous = 'on'
+        self.key_dispatch = {}
+        self.__vi_insert_mode = None
+        self._vi_command = None
+        self._vi_command_edit = None
+        self._vi_key_find_char = None
+        self._vi_key_find_direction = True
+        self._vi_yank_buffer = None
+        self._vi_multiplier1 = ''
+        self._vi_multiplier2 = ''
+        self._vi_undo_stack = []
+        self._vi_undo_cursor = -1
+        self._vi_current = None
+        self._vi_search_text = ''
+        self.vi_save_line ()
+        self.vi_set_insert_mode (True)
+        # make ' ' to ~ self insert
+        for c in range(ord(' '), 127):
+            self._bind_key('%s' % chr(c), self.vi_key)
+        self._bind_key('BackSpace', self.vi_backspace)
+        self._bind_key('Escape', self.vi_escape)
+        self._bind_key('Return', self.vi_accept_line)
+
+        self._bind_key('Left', self.backward_char)
+        self._bind_key('Right', self.forward_char)
+        self._bind_key('Home', self.beginning_of_line)
+        self._bind_key('End', self.end_of_line)
+        self._bind_key('Delete', self.delete_char)
+
+        self._bind_key('Control-d', self.vi_eof)
+        self._bind_key('Control-z', self.vi_eof)
+        self._bind_key('Control-r', self.vi_redo)
+        self._bind_key('Up', self.vi_arrow_up)
+        self._bind_key('Control-p', self.vi_up)
+        self._bind_key('Down', self.vi_arrow_down)
+        self._bind_key('Control-n', self.vi_down)
+        self._bind_key('Tab', self.vi_complete)
+#        self._bind_key('Control-e', self.emacs)
+
+    def vi_key (self, e):
+        if not self._vi_command:
+            self._vi_command = ViCommand (self)
+        elif self._vi_command.is_end:
+            if self._vi_command.is_edit:
+                self._vi_command_edit = self._vi_command
+            self._vi_command = ViCommand (self)
+        self._vi_command.add_char (e.char)
+
+    def vi_error (self):
+        self._bell ()
+
+    def vi_get_is_insert_mode (self):
+        return self.__vi_insert_mode
+    vi_is_insert_mode = property (vi_get_is_insert_mode)
+
+    def vi_escape (self, e):
+        if self.vi_is_insert_mode:
+            if self._vi_command:
+                self._vi_command.add_char (e.char)
+            else:
+                self._vi_command = ViCommand (self)
+            self.vi_set_insert_mode (False)
+            self.l_buffer.point=lineobj.PrevChar
+        elif self._vi_command and self._vi_command.is_replace_one:
+            self._vi_command.add_char (e.char)
+        else:
+            self.vi_error ()
+
+    def vi_backspace (self, e):
+        if self._vi_command:
+            self._vi_command.add_char (e.char)
+        else:
+            self._vi_do_backspace (self._vi_command)
+
+    def _vi_do_backspace (self, vi_cmd):
+        if self.vi_is_insert_mode or (self._vi_command and self._vi_command.is_search):
+            if self.l_buffer.point > 0:
+                self.l_buffer.point -= 1
+                if self.l_buffer.overwrite:
+                    try:
+                        prev = self._vi_undo_stack [self._vi_undo_cursor][1][self.l_buffer.point ]
+                        self.l_buffer.line_buffer [self.l_buffer.point] = prev
+                    except IndexError:
+                        del self.l_buffer.line_buffer [self.l_buffer.point ]
+                else:
+                    self.vi_save_line ()
+                    del self.l_buffer.line_buffer [self.l_buffer.point ]
+
+    def vi_accept_line (self, e):
+        if self._vi_command and self._vi_command.is_search:
+            self._vi_command.do_search ()
+            return False
+        self._vi_command = None
+        self.vi_set_insert_mode (True)
+        self._vi_undo_stack = []
+        self._vi_undo_cursor = -1
+        self._vi_current = None
+        return self.accept_line (e)
+
+    def vi_eof (self, e):
+        raise EOFError
+
+    def vi_set_insert_mode (self, value):
+        if self.__vi_insert_mode == value:
+            return
+        self.__vi_insert_mode = value
+        if value:
+            self.vi_save_line ()
+            self.cursor_size=25
+        else:
+            self.cursor_size=100
+
+    def vi_undo_restart (self):
+        tpl_undo = (self.l_buffer.point, self.l_buffer.line_buffer[:], )
+        self._vi_undo_stack = [tpl_undo]
+        self._vi_undo_cursor = 0
+
+    def vi_save_line (self):
+        if self._vi_undo_stack and self._vi_undo_cursor >= 0:
+            del self._vi_undo_stack [self._vi_undo_cursor + 1 : ]
+        # tpl_undo = (self.l_buffer.point, self.l_buffer[:], )
+        tpl_undo = (self.l_buffer.point, self.l_buffer.line_buffer[:], )
+        if not self._vi_undo_stack or self._vi_undo_stack[self._vi_undo_cursor][1] != tpl_undo[1]:
+            self._vi_undo_stack.append (tpl_undo)
+            self._vi_undo_cursor += 1
+
+    def vi_undo_prepare (self):
+        if self._vi_undo_cursor == len(self._vi_undo_stack)-1:
+            self.vi_save_line ()
+
+    def vi_undo (self, do_pop=True):
+        self.vi_undo_prepare ()
+        if not self._vi_undo_stack or self._vi_undo_cursor <= 0:
+            self.vi_error ()
+            return
+        self._vi_undo_cursor -= 1
+        self.vi_undo_assign ()
+
+    def vi_undo_all (self):
+        self.vi_undo_prepare ()
+        if self._vi_undo_cursor > 0:
+            self._vi_undo_cursor = 0
+            self.vi_undo_assign ()
+        else:
+            self.vi_error ()
+
+    def vi_undo_assign (self):
+        tpl_undo = self._vi_undo_stack [self._vi_undo_cursor]
+        self.l_buffer.line_buffer = tpl_undo [1][:]
+        self.l_buffer.point = tpl_undo [0]
+
+    def vi_redo (self, e):
+        if self._vi_undo_cursor >= len(self._vi_undo_stack)-1:
+            self.vi_error ()
+            return
+        self._vi_undo_cursor += 1
+        self.vi_undo_assign ()
+
+    def vi_search (self, rng):
+        for i in rng:
+            line_history = self._history.history [i]
+            pos = line_history.get_line_text().find (self._vi_search_text)
+            if pos >= 0:
+                self._history.history_cursor = i
+                self.l_buffer.line_buffer = list (line_history.line_buffer)
+                self.l_buffer.point = pos
+                self.vi_undo_restart ()
+                return True
+        self._bell ()
+        return False
+
+    def vi_search_first (self):
+        text = ''.join (self.l_buffer.line_buffer [1:])
+        if text:
+            self._vi_search_text = text
+            position = len (self._history.history) - 1
+        elif self._vi_search_text:
+            position = self._history.history_cursor - 1
+        else:
+            self.vi_error ()
+            self.vi_undo ()
+            return
+        if not self.vi_search (list(range(position, -1, -1))):
+            # Here: search text not found
+            self.vi_undo ()
+
+    def vi_search_again_backward (self):
+        self.vi_search (list(range(self._history.history_cursor-1, -1, -1)))
+
+    def vi_search_again_forward (self):
+        self.vi_search (list(range(self._history.history_cursor+1, len(self._history.history))))
+
+    def vi_up (self, e):
+        if self._history.history_cursor == len(self._history.history):
+            self._vi_current = self.l_buffer.line_buffer [:]
+        # self._history.previous_history (e)
+        self._history.previous_history (self.l_buffer)
+        if self.vi_is_insert_mode:
+            self.end_of_line (e)
+        else:
+            self.beginning_of_line (e)
+        self.vi_undo_restart ()
+
+    def vi_down (self, e):
+        if self._history.history_cursor >= len(self._history.history):
+            self.vi_error ()
+            return
+        if self._history.history_cursor < len(self._history.history) - 1:
+            # self._history.next_history (e)
+            self._history.next_history (self.l_buffer)
+            if self.vi_is_insert_mode:
+                self.end_of_line (e)
+            else:
+                self.beginning_of_line (e)
+            self.vi_undo_restart ()
+        elif self._vi_current is not None:
+            self._history.history_cursor = len(self._history.history)
+            self.l_buffer.line_buffer = self._vi_current
+            self.end_of_line (e)
+            if not self.vi_is_insert_mode and self.l_buffer.point > 0:
+                self.l_buffer.point -= 1
+            self._vi_current = None
+        else:
+            self.vi_error ()
+            return
+
+    def vi_arrow_up (self, e):
+        self.vi_set_insert_mode (True)
+        self.vi_up (e)
+        self.vi_save_line ()
+
+    def vi_arrow_down (self, e):
+        self.vi_set_insert_mode (True)
+        self.vi_down (e)
+        self.vi_save_line ()
+
+    def vi_complete (self, e):
+        text = self.l_buffer.get_line_text ()
+        if text and not text.isspace ():
+            return self.complete (e)
+        else:
+            return self.vi_key (e)
+
+# vi input states
+# sequence of possible states are in the order below
+_VI_BEGIN           = 'vi_begin'
+_VI_MULTI1          = 'vi_multi1'
+_VI_ACTION          = 'vi_action'
+_VI_MULTI2          = 'vi_multi2'
+_VI_MOTION          = 'vi_motion'
+_VI_MOTION_ARGUMENT = 'vi_motion_argument'
+_VI_REPLACE_ONE     = 'vi_replace_one'
+_VI_TEXT            = 'vi_text'
+_VI_SEARCH          = 'vi_search'
+_VI_END             = 'vi_end'
+
+# vi helper class
+class ViCommand:
+    def __init__ (self, readline):
+        self.readline = readline
+        self.lst_char = []
+        self.state = _VI_BEGIN
+        self.action = self.movement
+        self.motion = None
+        self.motion_argument = None
+        self.text = None
+        self.pos_motion = None
+        self.is_edit = False
+        self.is_overwrite = False
+        self.is_error = False
+        self.is_star = False
+        self.delete_left = 0
+        self.delete_right = 0
+        self.readline._vi_multiplier1 = ''
+        self.readline._vi_multiplier2 = ''
+        self.set_override_multiplier (0)
+        self.skip_multipler = False
+        self.tabstop = 4
+        self.dct_fcn = {
+            ord('$') : self.key_dollar,
+            ord('^') : self.key_hat,
+            ord(';') : self.key_semicolon,
+            ord(',') : self.key_comma,
+            ord('%') : self.key_percent,
+            ord('.') : self.key_dot,
+            ord('/') : self.key_slash,
+            ord('*') : self.key_star,
+            ord('|') : self.key_bar,
+            ord('~') : self.key_tilde,
+            8 : self.key_backspace,
+        }
+
+    def add_char (self, char):
+        self.lst_char.append (char)
+        if self.state == _VI_BEGIN and self.readline.vi_is_insert_mode:
+            self.readline.vi_save_line ()
+            self.state = _VI_TEXT
+        if self.state == _VI_SEARCH:
+            if char == '\x08':  # backspace
+                self.key_backspace (char)
+            else:
+                self.set_text (char)
+            return
+        if self.state == _VI_TEXT:
+            if char == '\x1b':  # escape
+                self.escape (char)
+            elif char == '\x09':  # tab
+                ts = self.tabstop
+                ws = ' ' * (ts - (self.readline.l_buffer.point%ts))
+                self.set_text (ws)
+            elif char == '\x08':  # backspace
+                self.key_backspace (char)
+            else:
+                self.set_text (char)
+            return
+        if self.state == _VI_MOTION_ARGUMENT:
+            self.set_motion_argument (char)
+            return
+        if self.state == _VI_REPLACE_ONE:
+            self.replace_one (char)
+            return
+        try:
+            fcn_instance = self.dct_fcn [ord(char)]
+        except:
+            fcn_instance = getattr (self, 'key_%s' % char, None)
+        if fcn_instance:
+            fcn_instance (char)
+            return
+        if char.isdigit ():
+            self.key_digit (char)
+            return
+        # Here: could not process key
+        self.error ()
+
+    def set_text (self, text):
+        if self.text is None:
+            self.text = text
+        else:
+            self.text += text
+        self.set_buffer (text)
+
+    def set_buffer (self, text):
+        for char in text:
+            if not self.char_isprint (char):
+                continue
+#             self.readline.l_buffer.insert_text(char)
+#             continue
+#             #overwrite in l_buffer obj
+            if self.is_overwrite:
+                if self.readline.l_buffer.point < len (self.readline.l_buffer.line_buffer):
+                    # self.readline.l_buffer[self.l_buffer.point]=char
+                    self.readline.l_buffer.line_buffer [self.readline.l_buffer.point] = char
+                else:
+                    # self.readline.l_buffer.insert_text(char)
+                    self.readline.l_buffer.line_buffer.append (char)
+            else:
+                # self.readline.l_buffer.insert_text(char)
+                self.readline.l_buffer.line_buffer.insert (self.readline.l_buffer.point, char)
+            self.readline.l_buffer.point += 1
+
+    def replace_one (self, char):
+        if char == '\x1b':  # escape
+            self.end ()
+            return
+        self.is_edit = True
+        self.readline.vi_save_line ()
+        times = self.get_multiplier ()
+        cursor = self.readline.l_buffer.point
+        self.readline.l_buffer.line_buffer [cursor : cursor + times] = char * times
+        if times > 1:
+            self.readline.l_buffer.point += (times - 1)
+        self.end ()
+
+    def char_isprint (self, char):
+        return ord(char) >= ord(' ') and ord(char) <= ord('~')
+
+    def key_dollar (self, char):
+        self.motion = self.motion_end_in_line
+        self.delete_right = 1
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_hat (self, char):
+        self.motion = self.motion_beginning_of_line
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_0 (self, char):
+        if self.state in [_VI_BEGIN, _VI_ACTION]:
+            self.key_hat (char)
+        else:
+            self.key_digit (char)
+
+    def key_digit (self, char):
+        if self.state in [_VI_BEGIN, _VI_MULTI1]:
+            self.readline._vi_multiplier1 += char
+            self.readline._vi_multiplier2 = ''
+            self.state = _VI_MULTI1
+        elif self.state in [_VI_ACTION, _VI_MULTI2]:
+            self.readline._vi_multiplier2 += char
+            self.state = _VI_MULTI2
+
+    def key_w (self, char):
+        if self.action == self.change:
+            self.key_e (char)
+            return
+        self.motion = self.motion_word_short
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_W (self, char):
+        if self.action == self.change:
+            self.key_E (char)
+            return
+        self.motion = self.motion_word_long
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_e (self, char):
+        self.motion = self.motion_end_short
+        self.state = _VI_MOTION
+        self.delete_right = 1
+        self.apply ()
+
+    def key_E (self, char):
+        self.motion = self.motion_end_long
+        self.state = _VI_MOTION
+        self.delete_right = 1
+        self.apply ()
+
+    def key_b (self, char):
+        self.motion = self.motion_back_short
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_B (self, char):
+        self.motion = self.motion_back_long
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_f (self, char):
+        self.readline._vi_key_find_direction = True
+        self.motion = self.motion_find_char_forward
+        self.delete_right = 1
+        self.state = _VI_MOTION_ARGUMENT
+
+    def key_F (self, char):
+        self.readline._vi_key_find_direction = False
+        self.motion = self.motion_find_char_backward
+        self.delete_left = 1
+        self.state = _VI_MOTION_ARGUMENT
+
+    def key_t (self, char):
+        self.motion = self.motion_to_char_forward
+        self.delete_right = 1
+        self.state = _VI_MOTION_ARGUMENT
+
+    def key_T (self, char):
+        self.motion = self.motion_to_char_backward
+        self.state = _VI_MOTION_ARGUMENT
+
+    def key_j (self, char):
+        self.readline.vi_down (ViEvent (char))
+        self.state = _VI_END
+
+    def key_k (self, char):
+        self.readline.vi_up (ViEvent (char))
+        self.state = _VI_END
+
+    def key_semicolon (self, char):
+        if self.readline._vi_key_find_char is None:
+            self.error ()
+            return
+        if self.readline._vi_key_find_direction:
+            self.motion = self.motion_find_char_forward
+        else:
+            self.motion = self.motion_find_char_backward
+        self.set_motion_argument (self.readline._vi_key_find_char)
+
+    def key_comma (self, char):
+        if self.readline._vi_key_find_char is None:
+            self.error ()
+            return
+        if self.readline._vi_key_find_direction:
+            self.motion = self.motion_find_char_backward
+        else:
+            self.motion = self.motion_find_char_forward
+        self.set_motion_argument (self.readline._vi_key_find_char)
+
+    def key_percent (self, char):
+        '''find matching <([{}])>'''
+        self.motion = self.motion_matching
+        self.delete_right = 1
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_dot (self, char):
+        vi_cmd_edit = self.readline._vi_command_edit
+        if not vi_cmd_edit:
+            return
+        if vi_cmd_edit.is_star:
+            self.key_star (char)
+            return
+        if self.has_multiplier ():
+            count = self.get_multiplier ()
+        else:
+            count = 0
+        # Create the ViCommand object after getting multipler from self
+        # Side effect of the ViCommand creation is resetting of global multipliers
+        vi_cmd = ViCommand (self.readline)
+        if count >= 1:
+            vi_cmd.set_override_multiplier (count)
+            vi_cmd_edit.set_override_multiplier (count)
+        elif vi_cmd_edit.override_multiplier:
+            vi_cmd.set_override_multiplier (vi_cmd_edit.override_multiplier)
+        for char in vi_cmd_edit.lst_char:
+            vi_cmd.add_char (char)
+        if vi_cmd_edit.is_overwrite and self.readline.l_buffer.point > 0:
+            self.readline.l_buffer.point -= 1
+        self.readline.vi_set_insert_mode (False)
+        self.end ()
+
+    def key_slash (self, char):
+        self.readline.vi_save_line ()
+        self.readline.l_buffer.line_buffer=['/']
+        self.readline.l_buffer.point= 1
+        self.state = _VI_SEARCH
+
+    def key_star (self, char):
+        self.is_star = True
+        self.is_edit = True
+        self.readline.vi_save_line ()
+        completions = self.readline._get_completions()
+        if completions:
+            text = ' '.join (completions) + ' '
+            self.readline.l_buffer.line_buffer [self.readline.begidx : self.readline.endidx + 1] = list (text)
+            prefix_len = self.readline.endidx - self.readline.begidx
+            self.readline.l_buffer.point += len(text) - prefix_len
+            self.readline.vi_set_insert_mode (True)
+        else:
+            self.error ()
+        self.state = _VI_TEXT
+
+    def key_bar (self, char):
+        self.motion = self.motion_column
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_tilde (self, char):
+        self.is_edit = True
+        self.readline.vi_save_line ()
+        for i in range (self.get_multiplier()):
+            try:
+                c = self.readline.l_buffer.line_buffer [self.readline.l_buffer.point]
+                if c.isupper ():
+                    self.readline.l_buffer.line_buffer [self.readline.l_buffer.point] = c.lower()
+                elif c.islower ():
+                    self.readline.l_buffer.line_buffer [self.readline.l_buffer.point] = c.upper()
+                self.readline.l_buffer.point += 1
+            except IndexError:
+                break
+        self.end ()
+
+    def key_h (self, char):
+        self.motion = self.motion_left
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_backspace (self, char):
+        if self.state in [_VI_TEXT, _VI_SEARCH]:
+            if self.text and len(self.text):
+                self.text = self.text [:-1]
+                try:
+                    # Remove backspaces for potential dot command
+                    self.lst_char.pop ()
+                    self.lst_char.pop ()
+                except IndexError:
+                    pass
+        else:
+            self.key_h (char)
+        self.readline._vi_do_backspace (self)
+        if self.state == _VI_SEARCH and not (self.readline.l_buffer.line_buffer):
+            self.state = _VI_BEGIN
+
+    def key_l (self, char):
+        self.motion = self.motion_right
+        self.state = _VI_MOTION
+        self.apply ()
+
+    def key_i (self, char):
+        self.is_edit = True
+        self.state = _VI_TEXT
+        self.readline.vi_set_insert_mode (True)
+
+    def key_I (self, char):
+        self.is_edit = True
+        self.state = _VI_TEXT
+        self.readline.vi_set_insert_mode (True)
+        self.readline.l_buffer.point = 0
+
+    def key_a (self, char):
+        self.is_edit = True
+        self.state = _VI_TEXT
+        self.readline.vi_set_insert_mode (True)
+        if len (self.readline.l_buffer.line_buffer):
+            self.readline.l_buffer.point += 1
+
+    def key_A (self, char):
+        self.is_edit = True
+        self.state = _VI_TEXT
+        self.readline.vi_set_insert_mode (True)
+        self.readline.l_buffer.point = len (self.readline.l_buffer.line_buffer)
+
+    def key_d (self, char):
+        self.is_edit = True
+        self.state = _VI_ACTION
+        self.action = self.delete
+
+    def key_D (self, char):
+        self.is_edit = True
+        self.state = _VI_ACTION
+        self.action = self.delete_end_of_line
+        self.apply ()
+
+    def key_x (self, char):
+        self.is_edit = True
+        self.state = _VI_ACTION
+        self.action = self.delete_char
+        self.apply ()
+
+    def key_X (self, char):
+        self.is_edit = True
+        self.state = _VI_ACTION
+        self.action = self.delete_prev_char
+        self.apply ()
+
+    def key_s (self, char):
+        self.is_edit = True
+        i1 = self.readline.l_buffer.point
+        i2 = self.readline.l_buffer.point + self.get_multiplier ()
+        self.skip_multipler = True
+        self.readline.vi_set_insert_mode (True)
+        del self.readline.l_buffer.line_buffer [i1 : i2]
+        self.state = _VI_TEXT
+
+    def key_S (self, char):
+        self.is_edit = True
+        self.readline.vi_set_insert_mode (True)
+        self.readline.l_buffer.line_buffer = []
+        self.readline.l_buffer.point = 0
+        self.state = _VI_TEXT
+
+    def key_c (self, char):
+        self.is_edit = True
+        self.state = _VI_ACTION
+        self.action = self.change
+
+    def key_C (self, char):
+        self.is_edit = True
+        self.readline.vi_set_insert_mode (True)
+        del self.readline.l_buffer.line_buffer [self.readline.l_buffer.point : ]
+        self.state = _VI_TEXT
+
+    def key_r (self, char):
+        self.state = _VI_REPLACE_ONE
+
+    def key_R (self, char):
+        self.is_edit = True
+        self.is_overwrite = True
+        self.readline.l_buffer.overwrite=True
+        self.readline.vi_set_insert_mode (True)
+        self.state = _VI_TEXT
+
+    def key_y (self, char):
+        self._state = _VI_ACTION
+        self.action = self.yank
+
+    def key_Y (self, char):
+        self.readline._vi_yank_buffer = self.readline.l_buffer.get_line_text()
+        self.end ()
+
+    def key_p (self, char):
+        if not self.readline._vi_yank_buffer:
+            return
+        self.is_edit = True
+        self.readline.vi_save_line ()
+        self.readline.l_buffer.point += 1
+        self.readline.l_buffer.insert_text (self.readline._vi_yank_buffer * self.get_multiplier ())
+        self.readline.l_buffer.point -= 1
+        self.state = _VI_END
+
+    def key_P (self, char):
+        if not self.readline._vi_yank_buffer:
+            return
+        self.is_edit = True
+        self.readline.vi_save_line ()
+        self.readline.l_buffer.insert_text (self.readline._vi_yank_buffer * self.get_multiplier ())
+        self.readline.l_buffer.point -= 1
+        self.state = _VI_END
+
+    def key_u (self, char):
+        self.readline.vi_undo ()
+        self.state = _VI_END
+
+    def key_U (self, char):
+        self.readline.vi_undo_all ()
+        self.state = _VI_END
+
+    def key_v (self, char):
+        editor = ViExternalEditor (self.readline.l_buffer.line_buffer)
+        self.readline.l_buffer.line_buffer = list (editor.result)
+        self.readline.l_buffer.point = 0
+        self.is_edit = True
+        self.state = _VI_END
+
+    def error (self):
+        self.readline._bell ()
+        self.is_error = True
+
+    def state_is_end (self):
+        return self.state == _VI_END
+    is_end = property (state_is_end)
+
+    def state_is_search (self):
+        return self.state == _VI_SEARCH
+    is_search = property (state_is_search)
+
+    def state_is_replace_one (self):
+        return self.state == _VI_REPLACE_ONE
+    is_replace_one = property (state_is_replace_one)
+
+    def do_search (self):
+        self.readline.vi_search_first ()
+        self.state = _VI_END
+
+    def key_n (self, char):
+        self.readline.vi_search_again_backward ()
+        self.state = _VI_END
+
+    def key_N (self, char):
+        self.readline.vi_search_again_forward ()
+        self.state = _VI_END
+
+    def motion_beginning_of_line (self, line, index=0, count=1, **kw):
+        return 0
+
+    def motion_end_in_line (self, line, index=0, count=1, **kw):
+        return max (0, len (self.readline.l_buffer.line_buffer)-1)
+
+    def motion_word_short (self, line, index=0, count=1, **kw):
+        return vi_pos_word_short (line, index, count)
+
+    def motion_word_long (self, line, index=0, count=1, **kw):
+        return vi_pos_word_long (line, index, count)
+
+    def motion_end_short (self, line, index=0, count=1, **kw):
+        return vi_pos_end_short (line, index, count)
+
+    def motion_end_long (self, line, index=0, count=1, **kw):
+        return vi_pos_end_long (line, index, count)
+
+    def motion_back_short (self, line, index=0, count=1, **kw):
+        return vi_pos_back_short (line, index, count)
+
+    def motion_back_long (self, line, index=0, count=1, **kw):
+        return vi_pos_back_long (line, index, count)
+
+    def motion_find_char_forward (self, line, index=0, count=1, char=None):
+        self.readline._vi_key_find_char = char
+        return vi_pos_find_char_forward (line, char, index, count)
+
+    def motion_find_char_backward (self, line, index=0, count=1, char=None):
+        self.readline._vi_key_find_char = char
+        return vi_pos_find_char_backward (line, char, index, count)
+
+    def motion_to_char_forward  (self, line, index=0, count=1, char=None):
+        return vi_pos_to_char_forward (line, char, index, count)
+
+    def motion_to_char_backward  (self, line, index=0, count=1, char=None):
+        return vi_pos_to_char_backward (line, char, index, count)
+
+    def motion_left (self, line, index=0, count=1, char=None):
+        return max (0, index - count)
+
+    def motion_right (self, line, index=0, count=1, char=None):
+        return min (len(line), index + count)
+
+    def motion_matching (self, line, index=0, count=1, char=None):
+        return vi_pos_matching (line, index)
+
+    def motion_column (self, line, index=0, count=1, char=None):
+        return max (0, count-1)
+
+    def has_multiplier (self):
+        return self.override_multiplier or self.readline._vi_multiplier1 or self.readline._vi_multiplier2
+
+    def get_multiplier (self):
+        if self.override_multiplier:
+            return int (self.override_multiplier)
+        if self.readline._vi_multiplier1 == '': m1 = 1
+        else: m1 = int(self.readline._vi_multiplier1)
+        if self.readline._vi_multiplier2 == '': m2 = 1
+        else: m2 = int(self.readline._vi_multiplier2)
+        return m1 * m2
+
+    def set_override_multiplier (self, count):
+        self.override_multiplier = count
+
+    def apply (self):
+        if self.motion:
+            self.pos_motion = self.motion (self.readline.l_buffer.line_buffer, self.readline.l_buffer.point,
+                    self.get_multiplier(), char=self.motion_argument)
+            if self.pos_motion < 0:
+                self.error ()
+                return
+        self.action ()
+        if self.state != _VI_TEXT:
+            self.end ()
+
+    def movement (self):
+        if self.pos_motion <= len(self.readline.l_buffer.line_buffer):
+            self.readline.l_buffer.point = self.pos_motion
+        else:
+            self.readline.l_buffer.point = len(self.readline.l_buffer.line_buffer) - 1
+
+    def yank (self):
+        if self.pos_motion > self.readline.l_buffer.point:
+            s = self.readline.l_buffer.line_buffer [self.readline.l_buffer.point : self.pos_motion + self.delete_right]
+        else:
+            index = max (0, self.pos_motion - self.delete_left)
+            s = self.readline.l_buffer.line_buffer [index : self.readline.l_buffer.point + self.delete_right]
+        self.readline._vi_yank_buffer = s
+
+    def delete (self):
+        self.readline.vi_save_line ()
+        self.yank ()
+#         point=lineobj.Point(self.readline.l_buffer)
+#         pm=self.pos_motion
+#         del self.readline.l_buffer[point:pm]
+#         return
+        if self.pos_motion > self.readline.l_buffer.point:
+            del self.readline.l_buffer.line_buffer [self.readline.l_buffer.point : self.pos_motion + self.delete_right]
+            if self.readline.l_buffer.point > len (self.readline.l_buffer.line_buffer):
+                self.readline.l_buffer.point = len (self.readline.l_buffer.line_buffer)
+        else:
+            index = max (0, self.pos_motion - self.delete_left)
+            del self.readline.l_buffer.line_buffer [index : self.readline.l_buffer.point + self.delete_right]
+            self.readline.l_buffer.point = index
+
+    def delete_end_of_line (self):
+        self.readline.vi_save_line ()
+        # del self.readline.l_buffer [self.readline.l_buffer.point : ]
+        line_text = self.readline.l_buffer.get_line_text ()
+        line_text = line_text [ : self.readline.l_buffer.point]
+        self.readline.l_buffer.set_line (line_text)
+        if self.readline.l_buffer.point > 0:
+            self.readline.l_buffer.point -= 1
+
+    def delete_char (self):
+#         point=lineobj.Point(self.readline.l_buffer)
+#         del self.readline.l_buffer[point:point+self.get_multiplier ()]
+#         return
+        self.pos_motion = self.readline.l_buffer.point + self.get_multiplier ()
+        self.delete ()
+        end = max (0, len (self.readline.l_buffer) - 1)
+        if self.readline.l_buffer.point > end:
+            self.readline.l_buffer.point = end
+
+    def delete_prev_char (self):
+        self.pos_motion = self.readline.l_buffer.point - self.get_multiplier ()
+        self.delete ()
+
+    def change (self):
+        self.readline.vi_set_insert_mode (True)
+        self.delete ()
+        self.skip_multipler = True
+        self.state = _VI_TEXT
+
+    def escape (self, char):
+        if self.state == _VI_TEXT:
+            if not self.skip_multipler:
+                times = self.get_multiplier ()
+                if times > 1 and self.text:
+                    extra = self.text * (times - 1)
+                    self.set_buffer (extra)
+        self.state = _VI_END
+
+    def set_motion_argument (self, char):
+        self.motion_argument = char
+        self.apply ()
+
+    def end (self):
+        self.state = _VI_END
+        if self.readline.l_buffer.point >= len(self.readline.l_buffer.line_buffer):
+            self.readline.l_buffer.point = max (0, len(self.readline.l_buffer.line_buffer) - 1)
+
+class ViExternalEditor:
+    def __init__ (self, line):
+        if type(line) is type([]):
+            line = ''.join (line)
+        file_tmp = self.get_tempfile ()
+        fp_tmp = self.file_open (file_tmp, 'w')
+        fp_tmp.write (line)
+        fp_tmp.close ()
+        self.run_editor (file_tmp)
+        fp_tmp = self.file_open (file_tmp, 'r')
+        self.result = fp_tmp.read ()
+        fp_tmp.close ()
+        self.file_remove (file_tmp)
+
+    def get_tempfile (self):
+        import tempfile
+        return tempfile.mktemp (prefix='readline-', suffix='.py')
+
+    def file_open (self, filename, mode):
+        return file (filename, mode)
+
+    def file_remove (self, filename):
+        os.remove (filename)
+
+    def get_editor (self):
+        try:
+            return os.environ ['EDITOR']
+        except KeyError:
+            return 'notepad'  # ouch
+
+    def run_editor (self, filename):
+        cmd = '%s %s' % (self.get_editor(), filename, )
+        self.run_command (cmd)
+
+    def run_command (self, command):
+        os.system (command)
+
+class ViEvent:
+    def __init__ (self, char):
+        self.char = char
+
+# vi standalone functions
+def vi_is_word (char):
+    log ('xx vi_is_word: type(%s), %s' % (type(char), char, ))
+    return char.isalpha() or char.isdigit() or char == '_'
+
+def vi_is_space (char):
+    return char.isspace ()
+
+def vi_is_word_or_space (char):
+    return vi_is_word (char) or vi_is_space (char)
+
+def vi_pos_word_short (line, index=0, count=1):
+    try:
+        for i in range(count):
+            in_word = vi_is_word (line[index])
+            if not in_word:
+                while not vi_is_word (line[index]):
+                    index += 1
+            else:
+                while vi_is_word (line[index]):
+                    index += 1
+            while vi_is_space (line[index]):
+                index += 1
+        return index
+    except IndexError:
+        return len(line)
+
+def vi_pos_word_long (line, index=0, count=1):
+    try:
+        for i in range(count):
+            in_space = vi_is_space (line[index])
+            if not in_space:
+                while not vi_is_space (line[index]):
+                    index += 1
+            while vi_is_space (line[index]):
+                index += 1
+        return index
+    except IndexError:
+        return len(line)
+
+def vi_pos_end_short (line, index=0, count=1):
+    try:
+        for i in range(count):
+            index += 1
+            while vi_is_space (line[index]):
+                index += 1
+            in_word = vi_is_word (line[index])
+            if not in_word:
+                while not vi_is_word_or_space (line[index]):
+                    index += 1
+            else:
+                while vi_is_word (line[index]):
+                    index += 1
+        return index - 1
+    except IndexError:
+        return max (0, len(line)-1)
+
+def vi_pos_end_long (line, index=0, count=1):
+    try:
+        for i in range(count):
+            index += 1
+            while vi_is_space (line[index]):
+                index += 1
+            while not vi_is_space (line[index]):
+                index += 1
+        return index - 1
+    except IndexError:
+        return max (0, len(line)-1)
+
+class vi_list (list):
+    '''This is a list that cannot have a negative index'''
+    def __getitem__ (self, key):
+        try:
+            if int(key) < 0:
+                raise IndexError
+        except ValueError:
+            pass
+        return list.__getitem__ (self, key)
+
+def vi_pos_back_short (line, index=0, count=1):
+    line = vi_list (line)
+    try:
+        for i in range(count):
+            index -= 1
+            while vi_is_space (line[index]):
+                index -= 1
+            in_word = vi_is_word (line[index])
+            if in_word:
+                while vi_is_word (line[index]):
+                    index -= 1
+            else:
+                while not vi_is_word_or_space (line[index]):
+                    index -= 1
+        return index + 1
+    except IndexError:
+        return 0
+
+def vi_pos_back_long (line, index=0, count=1):
+    line = vi_list (line)
+    try:
+        for i in range(count):
+            index -= 1
+            while vi_is_space (line[index]):
+                index -= 1
+            while not vi_is_space (line[index]):
+                index -= 1
+        return index + 1
+    except IndexError:
+        return 0
+
+def vi_pos_find_char_forward (line, char, index=0, count=1):
+    try:
+        for i in range(count):
+            index += 1
+            while line [index] != char:
+                index += 1
+        return index
+    except IndexError:
+        return -1
+
+def vi_pos_find_char_backward (line, char, index=0, count=1):
+    try:
+        for i in range(count):
+            index -= 1
+            while 1:
+                if index < 0:
+                    return -1
+                if line[index] == char:
+                    break
+                index -= 1
+        return index
+    except IndexError:
+        return -1
+
+def vi_pos_to_char_forward (line, char, index=0, count=1):
+    index = vi_pos_find_char_forward (line, char, index, count)
+    if index > 0:
+        return index - 1
+    return index
+
+def vi_pos_to_char_backward (line, char, index=0, count=1):
+    index = vi_pos_find_char_backward (line, char, index, count)
+    if index >= 0:
+        return index + 1
+    return index
+
+_vi_dct_matching = {
+    '<': ('>', +1), '>': ('<', -1),
+    '(': (')', +1), ')': ('(', -1),
+    '[': (']', +1), ']': ('[', -1),
+    '{': ('}', +1), '}': ('{', -1),
+}
+
+def vi_pos_matching (line, index=0):
+    '''find matching <([{}])>'''
+    anchor = None
+    target = None
+    delta = 1
+    count = 0
+    try:
+        while 1:
+            if anchor is None:
+                # first find anchor
+                try:
+                    target, delta = _vi_dct_matching [line [index]]
+                    anchor = line [index]
+                    count = 1
+                except KeyError:
+                    index += 1
+                    continue
+            else:
+                # Here the anchor has been found
+                # Need to get corresponding target
+                if index < 0:
+                    return -1
+                if line [index] == anchor:
+                    count += 1
+                elif line [index] == target:
+                    count -= 1
+                    if count == 0:
+                        return index
+            index += delta
+    except IndexError:
+        return -1
+
diff --git a/pyreadline/release.py b/pyreadline/release.py
new file mode 100644
index 0000000..625fc93
--- /dev/null
+++ b/pyreadline/release.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+"""Release data for the pyreadline project.
+
+$Id$"""
+
+#*****************************************************************************
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Name of the package for release purposes.  This is the name which labels
+# the tarballs and RPMs made by distutils, so it's best to lowercase it.
+name = 'pyreadline'
+
+# For versions with substrings (like 0.6.16.svn), use an extra . to separate
+# the new substring.  We have to avoid using either dashes or underscores,
+# because bdist_rpm does not accept dashes (an RPM) convention, and
+# bdist_deb does not accept underscores (a Debian convention).
+
+branch = ''
+
+version = '2.0'
+
+revision = '$Revision$'
+
+description = "A python implmementation of GNU readline."
+
+long_description = \
+"""
+The pyreadline package is a python implementation of GNU readline functionality
+it is based on the ctypes based UNC readline package by Gary Bishop. 
+It is not complete. It has been tested for use with windows 2000 and windows xp.
+
+Version 1.7.1 includes fixes for 64-bit windows, thanks to Christoph Gohlke for
+helping out.
+
+Version 1.7 will be the last release with compatibility with 2.4 and 2.5. The next
+major release will target 2.6, 2.7 and 3.x. The 1.7 series will only receive bugfixes
+from now on.
+
+Features:
+ *  keyboard text selection and copy/paste
+ *  Shift-arrowkeys for text selection
+ *  Control-c can be used for copy activate with allow_ctrl_c(True) in config file
+ *  Double tapping ctrl-c will raise a KeyboardInterrupt, use ctrl_c_tap_time_interval(x)
+    where x is your preferred tap time window, default 0.3 s.
+ *  paste pastes first line of content on clipboard. 
+ *  ipython_paste, pastes tab-separated data as list of lists or numpy array if all data is numeric
+ *  paste_mulitline_code pastes multi line code, removing any empty lines.
+ 
+ 
+ The latest development version is always available at the IPython subversion
+ repository_.
+
+.. _repository:
+ """
+
+license = 'BSD'
+
+authors = {'Jorgen' : ('Jorgen Stenarson','jorgen.stenarson@bostream.nu'),
+           'Gary':    ('Gary Bishop', ''),         
+           'Jack':    ('Jack Trainor', ''),         
+           }
+
+url = 'http://ipython.scipy.org/moin/PyReadline/Intro'
+
+download_url = 'https://launchpad.net/pyreadline/+download'
+
+platforms = ['Windows XP/2000/NT',
+             'Windows 95/98/ME']
+
+keywords = ['readline',
+            'pyreadline']
+
+classifiers = ['Development Status :: 5 - Production/Stable',
+               'Environment :: Console',
+               'Operating System :: Microsoft :: Windows',
+               'License :: OSI Approved :: BSD License',
+               'Programming Language :: Python :: 2.4',
+               'Programming Language :: Python :: 2.5',
+               'Programming Language :: Python :: 2.6',
+               'Programming Language :: Python :: 2.7',
+               'Programming Language :: Python :: 3.2',
+               ]
+               
+               
diff --git a/pyreadline/rlmain.py b/pyreadline/rlmain.py
new file mode 100644
index 0000000..443a74b
--- /dev/null
+++ b/pyreadline/rlmain.py
@@ -0,0 +1,591 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2003-2006 Gary Bishop.
+#       Copyright (C) 2006  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+''' an attempt to implement readline for Python in Python using ctypes'''
+import sys,os,re,time
+from glob import glob
+
+from . import release
+
+import pyreadline.lineeditor.lineobj as lineobj
+import pyreadline.lineeditor.history as history
+import pyreadline.clipboard as clipboard
+import pyreadline.console as console
+import pyreadline.logger as logger 
+
+from pyreadline.keysyms.common import make_KeyPress_from_keydescr
+from pyreadline.unicode_helper import ensure_unicode
+from .logger import log
+from .modes import editingmodes
+from .error import ReadlineError, GetSetError
+import collections
+
+in_ironpython = "IronPython" in sys.version
+if in_ironpython:#ironpython does not provide a prompt string to readline
+    import System    
+    default_prompt = ">>> "
+else:
+    default_prompt = ""
+    import pdb
+
+
+class MockConsoleError(Exception):
+    pass
+
+class MockConsole(object):
+    """object used during refactoring. Should raise errors when someone tries to use it.
+    """
+    def __setattr__(self, x):
+        raise MockConsoleError("Should not try to get attributes from MockConsole")
+
+    def cursor(self, size=50):
+        pass
+
+class BaseReadline(object):
+    def __init__(self):
+        self.allow_ctrl_c = False
+        self.ctrl_c_tap_time_interval = 0.3
+
+        self.debug = False
+        self.bell_style = 'none'
+        self.mark = -1
+        self.console=MockConsole()
+        self.disable_readline = False
+        # this code needs to follow l_buffer and history creation
+        self.editingmodes = [mode(self) for mode in editingmodes]
+        for mode in self.editingmodes:
+            mode.init_editing_mode(None)
+        self.mode = self.editingmodes[0]
+
+        self.read_inputrc()
+        log("\n".join(self.mode.rl_settings_to_string()))
+
+        self.callback = None
+
+    def parse_and_bind(self, string):
+        '''Parse and execute single line of a readline init file.'''
+        try:
+            log('parse_and_bind("%s")' % string)
+            if string.startswith('#'):
+                return
+            if string.startswith('set'):
+                m = re.compile(r'set\s+([-a-zA-Z0-9]+)\s+(.+)\s*$').match(string)
+                if m:
+                    var_name = m.group(1)
+                    val = m.group(2)
+                    try:
+                        setattr(self.mode, var_name.replace('-','_'), val)
+                    except AttributeError:
+                        log('unknown var="%s" val="%s"' % (var_name, val))
+                else:
+                    log('bad set "%s"' % string)
+                return
+            m = re.compile(r'\s*(.+)\s*:\s*([-a-zA-Z]+)\s*$').match(string)
+            if m:
+                key = m.group(1)
+                func_name = m.group(2)
+                py_name = func_name.replace('-', '_')
+                try:
+                    func = getattr(self.mode, py_name)
+                except AttributeError:
+                    log('unknown func key="%s" func="%s"' % (key, func_name))
+                    if self.debug:
+                        print('pyreadline parse_and_bind error, unknown function to bind: "%s"' % func_name)
+                    return
+                self.mode._bind_key(key, func)
+        except:
+            log('error')
+            raise
+
+    def _set_prompt(self, prompt):
+        self.mode.prompt = prompt
+        
+    def _get_prompt(self):
+        return self.mode.prompt
+    
+    prompt = property(_get_prompt, _set_prompt)
+
+
+    def get_line_buffer(self):
+        '''Return the current contents of the line buffer.'''
+        return self.mode.l_buffer.get_line_text()
+
+    def insert_text(self, string):
+        '''Insert text into the command line.'''
+        self.mode.insert_text(string)
+        
+    def read_init_file(self, filename=None): 
+        '''Parse a readline initialization file. The default filename is the last filename used.'''
+        log('read_init_file("%s")' % filename)
+
+    #History file book keeping methods (non-bindable)
+    
+    def add_history(self, line):
+        '''Append a line to the history buffer, as if it was the last line typed.'''
+        self.mode._history.add_history(line)
+
+    def get_current_history_length(self ):
+        '''Return the number of lines currently in the history.
+        (This is different from get_history_length(), which returns 
+        the maximum number of lines that will be written to a history file.)'''
+        return self.mode._history.get_current_history_length()
+
+    def get_history_length(self ):
+        '''Return the desired length of the history file.
+
+        Negative values imply unlimited history file size.'''
+        return self.mode._history.get_history_length()
+
+    def set_history_length(self, length): 
+        '''Set the number of lines to save in the history file.
+
+        write_history_file() uses this value to truncate the history file
+        when saving. Negative values imply unlimited history file size.
+        '''
+        self.mode._history.set_history_length(length)
+
+    def get_history_item(self, index): 
+        '''Return the current contents of history item at index.'''
+        return self.mode._history.get_history_item(index)
+
+    def clear_history(self):
+        '''Clear readline history'''
+        self.mode._history.clear_history()
+
+    def read_history_file(self, filename=None): 
+        '''Load a readline history file. The default filename is ~/.history.'''
+        if filename is None:
+            filename = self.mode._history.history_filename
+        log("read_history_file from %s"%ensure_unicode(filename))
+        self.mode._history.read_history_file(filename)
+
+    def write_history_file(self, filename=None): 
+        '''Save a readline history file. The default filename is ~/.history.'''
+        self.mode._history.write_history_file(filename)
+
+    #Completer functions
+
+    def set_completer(self, function=None): 
+        '''Set or remove the completer function.
+
+        If function is specified, it will be used as the new completer
+        function; if omitted or None, any completer function already
+        installed is removed. The completer function is called as
+        function(text, state), for state in 0, 1, 2, ..., until it returns a
+        non-string value. It should return the next possible completion
+        starting with text.
+        '''
+        log('set_completer')
+        self.mode.completer = function
+
+    def get_completer(self): 
+        '''Get the completer function. 
+        '''
+        log('get_completer')
+        return self.mode.completer
+
+    def get_begidx(self):
+        '''Get the beginning index of the readline tab-completion scope.'''
+        return self.mode.begidx
+
+    def get_endidx(self):
+        '''Get the ending index of the readline tab-completion scope.'''
+        return self.mode.endidx
+
+    def set_completer_delims(self, string):
+        '''Set the readline word delimiters for tab-completion.'''
+        self.mode.completer_delims = string
+
+    def get_completer_delims(self):
+        '''Get the readline word delimiters for tab-completion.'''
+        return self.mode.completer_delims.encode("ascii") 
+
+    def set_startup_hook(self, function=None): 
+        '''Set or remove the startup_hook function.
+
+        If function is specified, it will be used as the new startup_hook
+        function; if omitted or None, any hook function already installed is
+        removed. The startup_hook function is called with no arguments just
+        before readline prints the first prompt.
+
+        '''
+        self.mode.startup_hook = function
+
+    def set_pre_input_hook(self, function=None):
+        '''Set or remove the pre_input_hook function.
+
+        If function is specified, it will be used as the new pre_input_hook
+        function; if omitted or None, any hook function already installed is
+        removed. The pre_input_hook function is called with no arguments
+        after the first prompt has been printed and just before readline
+        starts reading input characters.
+
+        '''
+        self.mode.pre_input_hook = function
+
+#Functions that are not relevant for all Readlines but should at least have a NOP
+
+    def _bell(self):
+        pass
+
+#
+# Standard call, not available for all implementations
+#
+    
+    def readline(self, prompt=''):
+        raise NotImplementedError
+
+#
+# Callback interface
+#
+    def process_keyevent(self, keyinfo):
+        return self.mode.process_keyevent(keyinfo)
+        
+    def readline_setup(self, prompt=""):
+        return self.mode.readline_setup(prompt)
+
+    def keyboard_poll(self):
+        return self.mode._readline_from_keyboard_poll()
+
+    def callback_handler_install(self, prompt, callback):
+        '''bool readline_callback_handler_install ( string prompt, callback callback)
+        Initializes the readline callback interface and terminal, prints the prompt and returns immediately
+        '''
+        self.callback = callback
+        self.readline_setup(prompt)
+
+    def callback_handler_remove(self):
+        '''Removes a previously installed callback handler and restores terminal settings'''
+        self.callback = None
+
+    def callback_read_char(self):
+        '''Reads a character and informs the readline callback interface when a line is received'''
+        if self.keyboard_poll():
+            line = self.get_line_buffer() + '\n'
+            # however there is another newline added by
+            # self.mode.readline_setup(prompt) which is called by callback_handler_install
+            # this differs from GNU readline
+            self.add_history(self.mode.l_buffer)
+            # TADA:
+            self.callback(line)
+
+    def read_inputrc(self, #in 2.4 we cannot call expanduser with unicode string
+                     inputrcpath=os.path.expanduser("~/pyreadlineconfig.ini")):
+        modes = dict([(x.mode,x) for x in self.editingmodes])
+        mode = self.editingmodes[0].mode
+
+        def setmode(name):
+            self.mode = modes[name]
+
+        def bind_key(key, name):
+            import types
+            if isinstance(name, collections.Callable):
+                modes[mode]._bind_key(key, types.MethodType(name, modes[mode]))
+            elif hasattr(modes[mode], name):
+                modes[mode]._bind_key(key, getattr(modes[mode], name))
+            else:
+                print("Trying to bind unknown command '%s' to key '%s'"%(name, key))
+
+        def un_bind_key(key):
+            keyinfo = make_KeyPress_from_keydescr(key).tuple()
+            if keyinfo in modes[mode].key_dispatch:
+                del modes[mode].key_dispatch[keyinfo]
+
+        def bind_exit_key(key):
+            modes[mode]._bind_exit_key(key)
+            
+        def un_bind_exit_key(key):
+            keyinfo = make_KeyPress_from_keydescr(key).tuple()
+            if keyinfo in modes[mode].exit_dispatch:
+                del modes[mode].exit_dispatch[keyinfo]
+
+        def setkill_ring_to_clipboard(killring):
+            import pyreadline.lineeditor.lineobj 
+            pyreadline.lineeditor.lineobj.kill_ring_to_clipboard = killring
+
+        def sethistoryfilename(filename):
+            self.mode._history.history_filename=os.path.expanduser(filename)
+
+        def setbellstyle(mode):
+            self.bell_style = mode
+
+        def disable_readline(mode):
+            self.disable_readline = mode
+
+        def sethistorylength(length):
+            self.mode._history.history_length = int(length)
+
+        def allow_ctrl_c(mode):
+            log("allow_ctrl_c:%s:%s"%(self.allow_ctrl_c, mode))
+            self.allow_ctrl_c = mode
+ 
+        def setbellstyle(mode):
+            self.bell_style = mode
+ 
+        def show_all_if_ambiguous(mode):
+            self.mode.show_all_if_ambiguous = mode
+        
+        def ctrl_c_tap_time_interval(mode):
+            self.ctrl_c_tap_time_interval = mode
+        
+        def mark_directories(mode):
+            self.mode.mark_directories = mode
+        
+        def completer_delims(delims):
+            self.mode.completer_delims = delims
+        
+        def complete_filesystem(delims):
+            self.mode.complete_filesystem = delims.lower()
+
+        def enable_ipython_paste_for_paths(boolean):
+            self.mode.enable_ipython_paste_for_paths = boolean
+
+        def debug_output(on, filename="pyreadline_debug_log.txt"): #Not implemented yet
+            if on in ["on", "on_nologfile"]:
+                self.debug=True
+
+            if on == "on":
+                logger.start_file_log(filename)
+                logger.start_socket_log()
+                logger.log("STARTING LOG")
+            elif on == "on_nologfile":
+                logger.start_socket_log()
+                logger.log("STARTING LOG")
+            else:
+                logger.log("STOPING LOG")
+                logger.stop_file_log()
+                logger.stop_socket_log()
+        
+        _color_trtable={"black":0,      "darkred":4,  "darkgreen":2, 
+                        "darkyellow":6, "darkblue":1, "darkmagenta":5,
+                        "darkcyan":3,   "gray":7,     "red":4+8,
+                        "green":2+8,    "yellow":6+8, "blue":1+8,
+                        "magenta":5+8,  "cyan":3+8,   "white":7+8}
+        
+        def set_prompt_color(color):
+            self.prompt_color = self._color_trtable.get(color.lower(),7)            
+            
+        def set_input_color(color):
+            self.command_color=self._color_trtable.get(color.lower(),7)            
+
+        loc = {"branch":release.branch,
+               "version":release.version,
+               "mode":mode,
+               "modes":modes,
+               "set_mode":setmode,
+               "bind_key":bind_key,
+               "disable_readline":disable_readline,
+               "bind_exit_key":bind_exit_key,
+               "un_bind_key":un_bind_key,
+               "un_bind_exit_key":un_bind_exit_key,
+               "bell_style":setbellstyle,
+               "mark_directories":mark_directories,
+               "show_all_if_ambiguous":show_all_if_ambiguous,
+               "completer_delims":completer_delims,
+               "complete_filesystem":complete_filesystem,
+               "debug_output":debug_output,
+               "history_filename":sethistoryfilename,
+               "history_length":sethistorylength,
+               "set_prompt_color":set_prompt_color,
+               "set_input_color":set_input_color,
+               "allow_ctrl_c":allow_ctrl_c,
+               "ctrl_c_tap_time_interval":ctrl_c_tap_time_interval,
+               "kill_ring_to_clipboard":setkill_ring_to_clipboard,
+               "enable_ipython_paste_for_paths":enable_ipython_paste_for_paths,
+              }
+        if os.path.isfile(inputrcpath): 
+            try:
+                exec(compile(open(inputrcpath).read(), inputrcpath, 'exec'), loc, loc)
+            except Exception as x:
+                raise
+                import traceback
+                print("Error reading .pyinputrc", file=sys.stderr)
+                filepath,lineno=traceback.extract_tb(sys.exc_info()[2])[1][:2]
+                print("Line: %s in file %s"%(lineno, filepath), file=sys.stderr)
+                print(x, file=sys.stderr)
+                raise ReadlineError("Error reading .pyinputrc")
+
+
+
+class Readline(BaseReadline):
+    """Baseclass for readline based on a console
+    """
+    def __init__(self):
+        BaseReadline.__init__(self)
+        self.console = console.Console()
+        self.selection_color = self.console.saveattr<<4
+        self.command_color = None
+        self.prompt_color = None
+        self.size = self.console.size()
+
+        # variables you can control with parse_and_bind
+
+#  To export as readline interface
+
+
+##  Internal functions
+
+    def _bell(self):
+        '''ring the bell if requested.'''
+        if self.bell_style == 'none':
+            pass
+        elif self.bell_style == 'visible':
+            raise NotImplementedError("Bellstyle visible is not implemented yet.")
+        elif self.bell_style == 'audible':
+            self.console.bell()
+        else:
+            raise ReadlineError("Bellstyle %s unknown."%self.bell_style)
+
+    def _clear_after(self):
+        c = self.console
+        x, y = c.pos()
+        w, h = c.size()
+        c.rectangle((x, y, w+1, y+1))
+        c.rectangle((0, y+1, w, min(y+3,h)))
+
+    def _set_cursor(self):
+        c = self.console
+        xc, yc = self.prompt_end_pos
+        w, h = c.size()
+        xc += self.mode.l_buffer.visible_line_width()
+        while(xc >= w):
+            xc -= w
+            yc += 1
+        c.pos(xc, yc)
+
+    def _print_prompt(self):
+        c = self.console
+        x, y = c.pos()
+        
+        n = c.write_scrolling(self.prompt, self.prompt_color)
+        self.prompt_begin_pos = (x, y - n)
+        self.prompt_end_pos = c.pos()
+        self.size = c.size()
+
+    def _update_prompt_pos(self, n):
+        if n != 0:
+            bx, by = self.prompt_begin_pos
+            ex, ey = self.prompt_end_pos
+            self.prompt_begin_pos = (bx, by - n)
+            self.prompt_end_pos = (ex, ey - n)
+
+    def _update_line(self):
+        c = self.console
+        l_buffer = self.mode.l_buffer
+        c.cursor(0)         #Hide cursor avoiding flicking
+        c.pos(*self.prompt_begin_pos)
+        self._print_prompt()
+        ltext = l_buffer.quoted_text()
+        if l_buffer.enable_selection and (l_buffer.selection_mark >= 0):
+            start = len(l_buffer[:l_buffer.selection_mark].quoted_text())
+            stop  = len(l_buffer[:l_buffer.point].quoted_text())
+            if start > stop:
+                stop,start = start,stop
+            n = c.write_scrolling(ltext[:start], self.command_color)
+            n = c.write_scrolling(ltext[start:stop], self.selection_color)
+            n = c.write_scrolling(ltext[stop:], self.command_color)
+        else:
+            n = c.write_scrolling(ltext, self.command_color)
+
+        x, y = c.pos()       #Preserve one line for Asian IME(Input Method Editor) statusbar
+        w, h = c.size()
+        if (y >= h - 1) or (n > 0):
+            c.scroll_window(-1)
+            c.scroll((0, 0, w, h), 0, -1)
+            n += 1
+
+        self._update_prompt_pos(n)
+        if hasattr(c, "clear_to_end_of_window"): #Work around function for ironpython due 
+            c.clear_to_end_of_window()          #to System.Console's lack of FillFunction
+        else:
+            self._clear_after()
+        
+        #Show cursor, set size vi mode changes size in insert/overwrite mode
+        c.cursor(1, size=self.mode.cursor_size)  
+        self._set_cursor()
+
+
+    def callback_read_char(self):
+        #Override base to get automatic newline
+        '''Reads a character and informs the readline callback interface when a line is received'''
+        if self.keyboard_poll():
+            line = self.get_line_buffer() + '\n'
+            self.console.write("\r\n")
+            # however there is another newline added by
+            # self.mode.readline_setup(prompt) which is called by callback_handler_install
+            # this differs from GNU readline
+            self.add_history(self.mode.l_buffer)
+            # TADA:
+            self.callback(line)
+
+
+    def event_available(self):
+        return self.console.peek() or (len(self.paste_line_buffer) > 0)
+
+        
+    def _readline_from_keyboard(self):
+        while 1:
+            if self._readline_from_keyboard_poll():
+                break
+
+    def _readline_from_keyboard_poll(self):
+        pastebuffer = self.mode.paste_line_buffer
+        if len(pastebuffer) > 0:
+            #paste first line in multiline paste buffer
+            self.l_buffer = lineobj.ReadLineTextBuffer(pastebuffer[0])
+            self._update_line()
+            self.mode.paste_line_buffer = pastebuffer[1:]
+            return True
+
+        c = self.console
+        def nop(e):
+            pass
+        try:
+            event = c.getkeypress()
+        except KeyboardInterrupt:
+            event = self.handle_ctrl_c()
+        try:
+            result = self.mode.process_keyevent(event.keyinfo)
+        except EOFError:
+            logger.stop_logging()
+            raise
+        self._update_line()
+        return result
+
+    def readline_setup(self, prompt=''):
+        BaseReadline.readline_setup(self, prompt)
+        self._print_prompt()
+        self._update_line()
+
+    def readline(self, prompt=''):
+        self.readline_setup(prompt)
+        self.ctrl_c_timeout = time.time()
+        self._readline_from_keyboard()
+        self.console.write('\r\n')
+        log('returning(%s)' % self.get_line_buffer())
+        return self.get_line_buffer() + '\n'
+
+    def handle_ctrl_c(self):
+        from pyreadline.keysyms.common import KeyPress
+        from pyreadline.console.event import Event
+        log("KBDIRQ")
+        event = Event(0,0)
+        event.char = "c"
+        event.keyinfo = KeyPress("c", shift=False, control=True, 
+                                 meta=False, keyname=None)
+        if self.allow_ctrl_c:
+            now = time.time()
+            if (now - self.ctrl_c_timeout) < self.ctrl_c_tap_time_interval:
+                log("Raise KeyboardInterrupt")
+                raise KeyboardInterrupt
+            else:
+                self.ctrl_c_timeout = now
+        else:
+            raise KeyboardInterrupt
+        return event
+
diff --git a/pyreadline/unicode_helper.py b/pyreadline/unicode_helper.py
new file mode 100644
index 0000000..b848d60
--- /dev/null
+++ b/pyreadline/unicode_helper.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+#       Copyright (C) 2007  Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#*****************************************************************************
+import sys
+
+try:
+    pyreadline_codepage = sys.stdout.encoding
+except AttributeError:        
+    # This error occurs when pdb imports readline and doctest has replaced 
+    # stdout with stdout collector. We will assume ascii codepage
+    pyreadline_codepage = "ascii"
+
+if pyreadline_codepage is None:  
+    pyreadline_codepage = "ascii"
+
+if sys.version_info < (2, 6):
+    bytes = str
+
+PY3 = (sys.version_info >= (3, 0))
+
+def ensure_unicode(text):
+    """helper to ensure that text passed to WriteConsoleW is unicode"""
+    if isinstance(text, bytes):
+        try:
+            return text.decode(pyreadline_codepage, "replace")
+        except (LookupError, TypeError):
+            return text.decode("ascii", "replace")
+    return text
+
+def ensure_str(text):
+    """Convert unicode to str using pyreadline_codepage"""
+    if isinstance(text, str):
+        try:
+            return text.encode(pyreadline_codepage, "replace")
+        except (LookupError, TypeError):
+            return text.encode("ascii", "replace")
+    return text
+
+def biter(text):
+    if PY3 and isinstance(text, bytes):
+        return (s.to_bytes(1, 'big') for s in text)
+    else:
+        return iter(text)
diff --git a/pyreadline/windows_readline.py b/pyreadline/windows_readline.py
new file mode 100644
index 0000000..2d70def
--- /dev/null
+++ b/pyreadline/windows_readline.py
@@ -0,0 +1,79 @@
+# -*- coding: UTF-8 -*-
+#this file is needed in site-packages to emulate readline
+#necessary for rlcompleter since it relies on the existance
+#of a readline module
+from pyreadline.rlmain import Readline
+
+__all__ = [ 'parse_and_bind',
+            'get_line_buffer',
+            'insert_text',
+            'clear_history',
+            'read_init_file',
+            'read_history_file',
+            'write_history_file',
+            'get_current_history_length',
+            'get_history_length',
+            'get_history_item',
+            'set_history_length',
+            'set_startup_hook',
+            'set_pre_input_hook',
+            'set_completer',
+            'get_completer',
+            'get_begidx',
+            'get_endidx',
+            'set_completer_delims',
+            'get_completer_delims',
+            'add_history',
+            'callback_handler_install',
+            'callback_handler_remove',
+            'callback_read_char',] #Some other objects are added below
+
+
+# create a Readline object to contain the state
+rl = Readline()
+
+if rl.disable_readline:
+    def dummy(completer=""):
+        pass
+    for funk in __all__:
+        globals()[funk] = dummy
+else:
+    def GetOutputFile():
+        '''Return the console object used by readline so that it can be used for printing in color.'''
+        return rl.console
+    __all__.append("GetOutputFile")
+
+    import pyreadline.console as console
+
+    # make these available so this looks like the python readline module
+    read_init_file = rl.read_init_file
+    parse_and_bind = rl.parse_and_bind
+    clear_history = rl.clear_history
+    add_history = rl.add_history
+    insert_text = rl.insert_text
+
+    write_history_file = rl.write_history_file
+    read_history_file = rl.read_history_file
+
+    get_completer_delims = rl.get_completer_delims
+    get_current_history_length = rl.get_current_history_length
+    get_history_length = rl.get_history_length
+    get_history_item = rl.get_history_item
+    get_line_buffer = rl.get_line_buffer
+    set_completer = rl.set_completer
+    get_completer = rl.get_completer
+    get_begidx = rl.get_begidx
+    get_endidx = rl.get_endidx
+
+    set_completer_delims = rl.set_completer_delims
+    set_history_length = rl.set_history_length
+    set_pre_input_hook = rl.set_pre_input_hook
+    set_startup_hook = rl.set_startup_hook
+
+    callback_handler_install=rl.callback_handler_install
+    callback_handler_remove=rl.callback_handler_remove
+    callback_read_char=rl.callback_read_char
+
+    console.install_readline(rl.readline)
+
+__all__.append("rl")
\ No newline at end of file
diff --git a/queryfilters/__init__.py b/queryfilters/__init__.py
index dbd3c6c..f785286 100644
--- a/queryfilters/__init__.py
+++ b/queryfilters/__init__.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 def register_query_filter(name, class_):
     """Register a query filter.
diff --git a/queryfilters/base.py b/queryfilters/base.py
index df914db..797cdfa 100644
--- a/queryfilters/base.py
+++ b/queryfilters/base.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import copy
 
diff --git a/queryfilters/genericfilters.py b/queryfilters/genericfilters.py
index ce09c56..17095ff 100644
--- a/queryfilters/genericfilters.py
+++ b/queryfilters/genericfilters.py
@@ -16,9 +16,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import random, re
 from moleexceptions import FilterConfigException, FilterCreationError
diff --git a/requestfilters/__init__.py b/requestfilters/__init__.py
index 8259659..1c4702b 100644
--- a/requestfilters/__init__.py
+++ b/requestfilters/__init__.py
@@ -16,9 +16,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 
 def register_request_filter(name, class_):
diff --git a/requestfilters/base.py b/requestfilters/base.py
index 10c5f63..164b0d5 100644
--- a/requestfilters/base.py
+++ b/requestfilters/base.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import copy
 
diff --git a/requestfilters/urichanger.py b/requestfilters/urichanger.py
index 3007181..d1cc197 100644
--- a/requestfilters/urichanger.py
+++ b/requestfilters/urichanger.py
@@ -16,9 +16,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from urllib.parse import parse_qs, quote
 
diff --git a/responsefilters/__init__.py b/responsefilters/__init__.py
index 51a5277..facec61 100644
--- a/responsefilters/__init__.py
+++ b/responsefilters/__init__.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 def register_response_filter(name, class_):
     """Register a response filter.
diff --git a/responsefilters/base.py b/responsefilters/base.py
index 215c37a..b0aa9b5 100644
--- a/responsefilters/base.py
+++ b/responsefilters/base.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import copy
 
diff --git a/responsefilters/regexfilters.py b/responsefilters/regexfilters.py
index add15c5..841ab1a 100644
--- a/responsefilters/regexfilters.py
+++ b/responsefilters/regexfilters.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 import re, sre_constants
 from moleexceptions import FilterCreationError
diff --git a/themole.py b/themole.py
index fd5a1e6..92d28de 100644
--- a/themole.py
+++ b/themole.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from moleexceptions import MoleAttributeRequired, PageNotFound, ConnectionException
 from moleexceptions import DbmsDetectionFailed, CommentNotFound, ColumnNumberNotFound
@@ -175,8 +175,8 @@ class TheMole:
                     return
                 raise
 
-            if self._dbms_mole is None:
-                raise DbmsDetectionFailed()
+#            if self._dbms_mole is None:
+#                raise DbmsDetectionFailed()
 
             if self._dbms_mole.is_string_query():
                 output_manager.advance('Using string union technique.').line_break()
@@ -207,6 +207,7 @@ class TheMole:
         output_manager.echo_output = False
         try:
             if len(self.dumper.get_databases(self, field, 1)) > 0:
+                self.injectable_field = field
                 return True
         except QueryError:
             return False
diff --git a/threader.py b/threader.py
index 235574a..4b256d9 100644
--- a/threader.py
+++ b/threader.py
@@ -18,9 +18,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from threading import Thread, Event, Lock
 from moleexceptions import ConnectionException, QueryError
diff --git a/xmlexporter.py b/xmlexporter.py
index e0f834d..d241ac5 100644
--- a/xmlexporter.py
+++ b/xmlexporter.py
@@ -17,9 +17,9 @@
 # Developed by: Nasel(http://www.nasel.com.ar)
 #
 # Authors:
-# Matías Fontanini
+# Matias Fontanini
 # Santiago Alessandri
-# Gastón Traberg
+# Gaston Traberg
 
 from pickle import dumps, loads
 

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details