changeset 2329:ad2889f48843 vim73

Added support for Python 3. (Roland Puntaier)
author Bram Moolenaar <bram@vim.org>
date Sat, 17 Jul 2010 21:19:38 +0200
parents 15379284e55a
children ea4bf6df1a8a
files Filelist Makefile runtime/autoload/python3complete.vim runtime/doc/todo.txt runtime/syntax/vim.vim src/Make_bc5.mak src/Make_cyg.mak src/Make_ming.mak src/Make_mvc.mak src/Makefile src/auto/configure src/buffer.c src/config.h.in src/config.mk.in src/configure.in src/eval.c src/ex_cmds.h src/ex_docmd.c src/globals.h src/if_python.c src/if_python3.c src/main.c src/proto.h src/proto/if_python3.pro src/structs.h src/version.c src/vim.h src/window.c
diffstat 28 files changed, 4229 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -216,6 +216,7 @@ SRC_DOS_UNIX =	\
 		src/if_perl.xs \
 		src/if_perlsfio.c \
 		src/if_python.c \
+		src/if_python3.c \
 		src/if_ruby.c \
 		src/if_sniff.h \
 		src/if_tcl.c \
@@ -225,6 +226,7 @@ SRC_DOS_UNIX =	\
 		src/proto/if_perl.pro \
 		src/proto/if_perlsfio.pro \
 		src/proto/if_python.pro \
+		src/proto/if_python3.pro \
 		src/proto/if_ruby.pro \
 		src/proto/if_tcl.pro \
 		src/typemap \
--- a/Makefile
+++ b/Makefile
@@ -80,8 +80,9 @@ DOSBIN_S =  dosbin_s
 #   runtime/doc/*.txt and nsis/gvim.nsi. Other things in README_os2.txt.  For a
 #   minor/major version: src/GvimExt/GvimExt.reg, src/vim.def, src/vim16.def.
 # - Correct included_patches[] in src/version.c.
-# - Compile Vim with GTK, Perl, Python, TCL, Ruby, MZscheme, Lua (if you can
-#   make it work), Cscope and "huge" features.  Exclude workshop and SNiFF.
+# - Compile Vim with GTK, Perl, Python, Python3, TCL, Ruby, MZscheme, Lua (if
+#   you can make it work), Cscope and "huge" features.  Exclude workshop and
+#   SNiFF.
 # - With these features: "make proto" (requires cproto and Motif installed;
 #   ignore warnings for missing include files, fix problems for syntax errors).
 # - With these features: "make depend" (works best with gcc).
new file mode 100644
--- /dev/null
+++ b/runtime/autoload/python3complete.vim
@@ -0,0 +1,606 @@
+"python3complete.vim - Omni Completion for python
+" Maintainer: Aaron Griffin <aaronmgriffin@gmail.com>
+" Version: 0.9
+" Last Updated: 18 Jun 2009
+"
+" Roland Puntaier: this file contains adaptations for python3 and is parallel to pythoncomplete.vim
+"
+" Changes
+" TODO:
+" 'info' item output can use some formatting work
+" Add an "unsafe eval" mode, to allow for return type evaluation
+" Complete basic syntax along with import statements
+"   i.e. "import url<c-x,c-o>"
+" Continue parsing on invalid line??
+"
+" v 0.9
+"   * Fixed docstring parsing for classes and functions
+"   * Fixed parsing of *args and **kwargs type arguments
+"   * Better function param parsing to handle things like tuples and
+"     lambda defaults args
+"
+" v 0.8
+"   * Fixed an issue where the FIRST assignment was always used instead of
+"   using a subsequent assignment for a variable
+"   * Fixed a scoping issue when working inside a parameterless function
+"
+"
+" v 0.7
+"   * Fixed function list sorting (_ and __ at the bottom)
+"   * Removed newline removal from docs.  It appears vim handles these better in
+"   recent patches
+"
+" v 0.6:
+"   * Fixed argument completion
+"   * Removed the 'kind' completions, as they are better indicated
+"   with real syntax
+"   * Added tuple assignment parsing (whoops, that was forgotten)
+"   * Fixed import handling when flattening scope
+"
+" v 0.5:
+" Yeah, I skipped a version number - 0.4 was never public.
+"  It was a bugfix version on top of 0.3.  This is a complete
+"  rewrite.
+"
+
+if !has('python3')
+    echo "Error: Required vim compiled with +python3"
+    finish
+endif
+
+function! python3complete#Complete(findstart, base)
+    "findstart = 1 when we need to get the text length
+    if a:findstart == 1
+        let line = getline('.')
+        let idx = col('.')
+        while idx > 0
+            let idx -= 1
+            let c = line[idx]
+            if c =~ '\w'
+                continue
+            elseif ! c =~ '\.'
+                let idx = -1
+                break
+            else
+                break
+            endif
+        endwhile
+
+        return idx
+    "findstart = 0 when we need to return the list of completions
+    else
+        "vim no longer moves the cursor upon completion... fix that
+        let line = getline('.')
+        let idx = col('.')
+        let cword = ''
+        while idx > 0
+            let idx -= 1
+            let c = line[idx]
+            if c =~ '\w' || c =~ '\.'
+                let cword = c . cword
+                continue
+            elseif strlen(cword) > 0 || idx == 0
+                break
+            endif
+        endwhile
+        execute "py3 vimpy3complete('" . cword . "', '" . a:base . "')"
+        return g:python3complete_completions
+    endif
+endfunction
+
+function! s:DefPython()
+py3 << PYTHONEOF
+import sys, tokenize, io, types
+from token import NAME, DEDENT, NEWLINE, STRING
+
+debugstmts=[]
+def dbg(s): debugstmts.append(s)
+def showdbg():
+    for d in debugstmts: print("DBG: %s " % d)
+
+def vimpy3complete(context,match):
+    global debugstmts
+    debugstmts = []
+    try:
+        import vim
+        cmpl = Completer()
+        cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')"))
+        all = cmpl.get_completions(context,match)
+        all.sort(key=lambda x:x['abbr'].replace('_','z'))
+        dictstr = '['
+        # have to do this for double quoting
+        for cmpl in all:
+            dictstr += '{'
+            for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x])
+            dictstr += '"icase":0},'
+        if dictstr[-1] == ',': dictstr = dictstr[:-1]
+        dictstr += ']'
+        #dbg("dict: %s" % dictstr)
+        vim.command("silent let g:python3complete_completions = %s" % dictstr)
+        #dbg("Completion dict:\n%s" % all)
+    except vim.error:
+        dbg("VIM Error: %s" % vim.error)
+
+class Completer(object):
+    def __init__(self):
+       self.compldict = {}
+       self.parser = PyParser()
+
+    def evalsource(self,text,line=0):
+        sc = self.parser.parse(text,line)
+        src = sc.get_code()
+        dbg("source: %s" % src)
+        try: exec(src,self.compldict)
+        except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
+        for l in sc.locals:
+            try: exec(l,self.compldict)
+            except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))
+
+    def _cleanstr(self,doc):
+        return doc.replace('"',' ').replace("'",' ')
+
+    def get_arguments(self,func_obj):
+        def _ctor(class_ob):
+            try: return class_ob.__init__
+            except AttributeError:
+                for base in class_ob.__bases__:
+                    rc = _ctor(base)
+                    if rc is not None: return rc
+            return None
+
+        arg_offset = 1
+        if type(func_obj) == type: func_obj = _ctor(func_obj)
+        elif type(func_obj) == types.MethodType: arg_offset = 1
+        else: arg_offset = 0
+
+        arg_text=''
+        if type(func_obj) in [types.FunctionType, types.LambdaType,types.MethodType]:
+            try:
+                cd = func_obj.__code__
+                real_args = cd.co_varnames[arg_offset:cd.co_argcount]
+                defaults = func_obj.__defaults__ or []
+                defaults = ["=%s" % name for name in defaults]
+                defaults = [""] * (len(real_args)-len(defaults)) + defaults
+                items = [a+d for a,d in zip(real_args,defaults)]
+                if func_obj.__code__.co_flags & 0x4:
+                    items.append("...")
+                if func_obj.__code__.co_flags & 0x8:
+                    items.append("***")
+                arg_text = (','.join(items)) + ')'
+            except:
+                dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1]))
+                pass
+        if len(arg_text) == 0:
+            # The doc string sometimes contains the function signature
+            #  this works for alot of C modules that are part of the
+            #  standard library
+            doc = func_obj.__doc__
+            if doc:
+                doc = doc.lstrip()
+                pos = doc.find('\n')
+                if pos > 0:
+                    sigline = doc[:pos]
+                    lidx = sigline.find('(')
+                    ridx = sigline.find(')')
+                    if lidx > 0 and ridx > 0:
+                        arg_text = sigline[lidx+1:ridx] + ')'
+        if len(arg_text) == 0: arg_text = ')'
+        return arg_text
+
+    def get_completions(self,context,match):
+        #dbg("get_completions('%s','%s')" % (context,match))
+        stmt = ''
+        if context: stmt += str(context)
+        if match: stmt += str(match)
+        try:
+            result = None
+            all = {}
+            ridx = stmt.rfind('.')
+            if len(stmt) > 0 and stmt[-1] == '(':
+                result = eval(_sanitize(stmt[:-1]), self.compldict)
+                doc = result.__doc__
+                if doc is None: doc = ''
+                args = self.get_arguments(result)
+                return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}]
+            elif ridx == -1:
+                match = stmt
+                all = self.compldict
+            else:
+                match = stmt[ridx+1:]
+                stmt = _sanitize(stmt[:ridx])
+                result = eval(stmt, self.compldict)
+                all = dir(result)
+
+            dbg("completing: stmt:%s" % stmt)
+            completions = []
+
+            try: maindoc = result.__doc__
+            except: maindoc = ' '
+            if maindoc is None: maindoc = ' '
+            for m in all:
+                if m == "_PyCmplNoType": continue #this is internal
+                try:
+                    dbg('possible completion: %s' % m)
+                    if m.find(match) == 0:
+                        if result is None: inst = all[m]
+                        else: inst = getattr(result,m)
+                        try: doc = inst.__doc__
+                        except: doc = maindoc
+                        typestr = str(inst)
+                        if doc is None or doc == '': doc = maindoc
+
+                        wrd = m[len(match):]
+                        c = {'word':wrd, 'abbr':m,  'info':self._cleanstr(doc)}
+                        if "function" in typestr:
+                            c['word'] += '('
+                            c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
+                        elif "method" in typestr:
+                            c['word'] += '('
+                            c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
+                        elif "module" in typestr:
+                            c['word'] += '.'
+                        elif "type" in typestr:
+                            c['word'] += '('
+                            c['abbr'] += '('
+                        completions.append(c)
+                except:
+                    i = sys.exc_info()
+                    dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
+            return completions
+        except:
+            i = sys.exc_info()
+            dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
+            return []
+
+class Scope(object):
+    def __init__(self,name,indent,docstr=''):
+        self.subscopes = []
+        self.docstr = docstr
+        self.locals = []
+        self.parent = None
+        self.name = name
+        self.indent = indent
+
+    def add(self,sub):
+        #print('push scope: [%s@%s]' % (sub.name,sub.indent))
+        sub.parent = self
+        self.subscopes.append(sub)
+        return sub
+
+    def doc(self,str):
+        """ Clean up a docstring """
+        d = str.replace('\n',' ')
+        d = d.replace('\t',' ')
+        while d.find('  ') > -1: d = d.replace('  ',' ')
+        while d[0] in '"\'\t ': d = d[1:]
+        while d[-1] in '"\'\t ': d = d[:-1]
+        dbg("Scope(%s)::docstr = %s" % (self,d))
+        self.docstr = d
+
+    def local(self,loc):
+        self._checkexisting(loc)
+        self.locals.append(loc)
+
+    def copy_decl(self,indent=0):
+        """ Copy a scope's declaration only, at the specified indent level - not local variables """
+        return Scope(self.name,indent,self.docstr)
+
+    def _checkexisting(self,test):
+        "Convienance function... keep out duplicates"
+        if test.find('=') > -1:
+            var = test.split('=')[0].strip()
+            for l in self.locals:
+                if l.find('=') > -1 and var == l.split('=')[0].strip():
+                    self.locals.remove(l)
+
+    def get_code(self):
+        str = ""
+        if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n'
+        for l in self.locals:
+            if l.startswith('import'): str += l+'\n'
+        str += 'class _PyCmplNoType:\n    def __getattr__(self,name):\n        return None\n'
+        for sub in self.subscopes:
+            str += sub.get_code()
+        for l in self.locals:
+            if not l.startswith('import'): str += l+'\n'
+
+        return str
+
+    def pop(self,indent):
+        #print('pop scope: [%s] to [%s]' % (self.indent,indent))
+        outer = self
+        while outer.parent != None and outer.indent >= indent:
+            outer = outer.parent
+        return outer
+
+    def currentindent(self):
+        #print('parse current indent: %s' % self.indent)
+        return '    '*self.indent
+
+    def childindent(self):
+        #print('parse child indent: [%s]' % (self.indent+1))
+        return '    '*(self.indent+1)
+
+class Class(Scope):
+    def __init__(self, name, supers, indent, docstr=''):
+        Scope.__init__(self,name,indent, docstr)
+        self.supers = supers
+    def copy_decl(self,indent=0):
+        c = Class(self.name,self.supers,indent, self.docstr)
+        for s in self.subscopes:
+            c.add(s.copy_decl(indent+1))
+        return c
+    def get_code(self):
+        str = '%sclass %s' % (self.currentindent(),self.name)
+        if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers)
+        str += ':\n'
+        if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
+        if len(self.subscopes) > 0:
+            for s in self.subscopes: str += s.get_code()
+        else:
+            str += '%spass\n' % self.childindent()
+        return str
+
+
+class Function(Scope):
+    def __init__(self, name, params, indent, docstr=''):
+        Scope.__init__(self,name,indent, docstr)
+        self.params = params
+    def copy_decl(self,indent=0):
+        return Function(self.name,self.params,indent, self.docstr)
+    def get_code(self):
+        str = "%sdef %s(%s):\n" % \
+            (self.currentindent(),self.name,','.join(self.params))
+        if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
+        str += "%spass\n" % self.childindent()
+        return str
+
+class PyParser:
+    def __init__(self):
+        self.top = Scope('global',0)
+        self.scope = self.top
+
+    def _parsedotname(self,pre=None):
+        #returns (dottedname, nexttoken)
+        name = []
+        if pre is None:
+            tokentype, token, indent = self.donext()
+            if tokentype != NAME and token != '*':
+                return ('', token)
+        else: token = pre
+        name.append(token)
+        while True:
+            tokentype, token, indent = self.donext()
+            if token != '.': break
+            tokentype, token, indent = self.donext()
+            if tokentype != NAME: break
+            name.append(token)
+        return (".".join(name), token)
+
+    def _parseimportlist(self):
+        imports = []
+        while True:
+            name, token = self._parsedotname()
+            if not name: break
+            name2 = ''
+            if token == 'as': name2, token = self._parsedotname()
+            imports.append((name, name2))
+            while token != "," and "\n" not in token:
+                tokentype, token, indent = self.donext()
+            if token != ",": break
+        return imports
+
+    def _parenparse(self):
+        name = ''
+        names = []
+        level = 1
+        while True:
+            tokentype, token, indent = self.donext()
+            if token in (')', ',') and level == 1:
+                if '=' not in name: name = name.replace(' ', '')
+                names.append(name.strip())
+                name = ''
+            if token == '(':
+                level += 1
+                name += "("
+            elif token == ')':
+                level -= 1
+                if level == 0: break
+                else: name += ")"
+            elif token == ',' and level == 1:
+                pass
+            else:
+                name += "%s " % str(token)
+        return names
+
+    def _parsefunction(self,indent):
+        self.scope=self.scope.pop(indent)
+        tokentype, fname, ind = self.donext()
+        if tokentype != NAME: return None
+
+        tokentype, open, ind = self.donext()
+        if open != '(': return None
+        params=self._parenparse()
+
+        tokentype, colon, ind = self.donext()
+        if colon != ':': return None
+
+        return Function(fname,params,indent)
+
+    def _parseclass(self,indent):
+        self.scope=self.scope.pop(indent)
+        tokentype, cname, ind = self.donext()
+        if tokentype != NAME: return None
+
+        super = []
+        tokentype, thenext, ind = self.donext()
+        if thenext == '(':
+            super=self._parenparse()
+        elif thenext != ':': return None
+
+        return Class(cname,super,indent)
+
+    def _parseassignment(self):
+        assign=''
+        tokentype, token, indent = self.donext()
+        if tokentype == tokenize.STRING or token == 'str':  
+            return '""'
+        elif token == '(' or token == 'tuple':
+            return '()'
+        elif token == '[' or token == 'list':
+            return '[]'
+        elif token == '{' or token == 'dict':
+            return '{}'
+        elif tokentype == tokenize.NUMBER:
+            return '0'
+        elif token == 'open' or token == 'file':
+            return 'file'
+        elif token == 'None':
+            return '_PyCmplNoType()'
+        elif token == 'type':
+            return 'type(_PyCmplNoType)' #only for method resolution
+        else:
+            assign += token
+            level = 0
+            while True:
+                tokentype, token, indent = self.donext()
+                if token in ('(','{','['):
+                    level += 1
+                elif token in (']','}',')'):
+                    level -= 1
+                    if level == 0: break
+                elif level == 0:
+                    if token in (';','\n'): break
+                    assign += token
+        return "%s" % assign
+
+    def donext(self):
+        type, token, (lineno, indent), end, self.parserline = next(self.gen)
+        if lineno == self.curline:
+            #print('line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name))
+            self.currentscope = self.scope
+        return (type, token, indent)
+
+    def _adjustvisibility(self):
+        newscope = Scope('result',0)
+        scp = self.currentscope
+        while scp != None:
+            if type(scp) == Function:
+                slice = 0
+                #Handle 'self' params
+                if scp.parent != None and type(scp.parent) == Class:
+                    slice = 1
+                    newscope.local('%s = %s' % (scp.params[0],scp.parent.name))
+                for p in scp.params[slice:]:
+                    i = p.find('=')
+                    if len(p) == 0: continue
+                    pvar = ''
+                    ptype = ''
+                    if i == -1:
+                        pvar = p
+                        ptype = '_PyCmplNoType()'
+                    else:
+                        pvar = p[:i]
+                        ptype = _sanitize(p[i+1:])
+                    if pvar.startswith('**'):
+                        pvar = pvar[2:]
+                        ptype = '{}'
+                    elif pvar.startswith('*'):
+                        pvar = pvar[1:]
+                        ptype = '[]'
+
+                    newscope.local('%s = %s' % (pvar,ptype))
+
+            for s in scp.subscopes:
+                ns = s.copy_decl(0)
+                newscope.add(ns)
+            for l in scp.locals: newscope.local(l)
+            scp = scp.parent
+
+        self.currentscope = newscope
+        return self.currentscope
+
+    #p.parse(vim.current.buffer[:],vim.eval("line('.')"))
+    def parse(self,text,curline=0):
+        self.curline = int(curline)
+        buf = io.StringIO(''.join(text) + '\n')
+        self.gen = tokenize.generate_tokens(buf.readline)
+        self.currentscope = self.scope
+
+        try:
+            freshscope=True
+            while True:
+                tokentype, token, indent = self.donext()
+                #dbg( 'main: token=[%s] indent=[%s]' % (token,indent))
+
+                if tokentype == DEDENT or token == "pass":
+                    self.scope = self.scope.pop(indent)
+                elif token == 'def':
+                    func = self._parsefunction(indent)
+                    if func is None:
+                        print("function: syntax error...")
+                        continue
+                    dbg("new scope: function")
+                    freshscope = True
+                    self.scope = self.scope.add(func)
+                elif token == 'class':
+                    cls = self._parseclass(indent)
+                    if cls is None:
+                        print("class: syntax error...")
+                        continue
+                    freshscope = True
+                    dbg("new scope: class")
+                    self.scope = self.scope.add(cls)
+                    
+                elif token == 'import':
+                    imports = self._parseimportlist()
+                    for mod, alias in imports:
+                        loc = "import %s" % mod
+                        if len(alias) > 0: loc += " as %s" % alias
+                        self.scope.local(loc)
+                    freshscope = False
+                elif token == 'from':
+                    mod, token = self._parsedotname()
+                    if not mod or token != "import":
+                        print("from: syntax error...")
+                        continue
+                    names = self._parseimportlist()
+                    for name, alias in names:
+                        loc = "from %s import %s" % (mod,name)
+                        if len(alias) > 0: loc += " as %s" % alias
+                        self.scope.local(loc)
+                    freshscope = False
+                elif tokentype == STRING:
+                    if freshscope: self.scope.doc(token)
+                elif tokentype == NAME:
+                    name,token = self._parsedotname(token) 
+                    if token == '=':
+                        stmt = self._parseassignment()
+                        dbg("parseassignment: %s = %s" % (name, stmt))
+                        if stmt != None:
+                            self.scope.local("%s = %s" % (name,stmt))
+                    freshscope = False
+        except StopIteration: #thrown on EOF
+            pass
+        except:
+            dbg("parse error: %s, %s @ %s" %
+                (sys.exc_info()[0], sys.exc_info()[1], self.parserline))
+        return self._adjustvisibility()
+
+def _sanitize(str):
+    val = ''
+    level = 0
+    for c in str:
+        if c in ('(','{','['):
+            level += 1
+        elif c in (']','}',')'):
+            level -= 1
+        elif level == 0:
+            val += c
+    return val
+
+sys.path.extend(['.','..'])
+PYTHONEOF
+endfunction
+
+call s:DefPython()
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1089,17 +1089,12 @@ Before (beta) release 7.3:
 - Add fixes for 7.2 to version7.txt
 - Add hg history to version7.txt
 - Remove UF_VERSION_CRYPT_PREV and UF_VERSION_PREV.
+- Build the MS-Windows version with Python 2.6.5 and 3.1.2?
 
 Before release 7.3:
 - Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23)
 
 Vim 7.3:
-Patches to possibly include:
--   Patch for Python 3 support. (Roland Puntaier, 2009 Sep 22)
-    Includes changes for omnicompletion.
-    Needs some more testing.
-    Update 2010 Apr 20, patch by Andy Kittner, May 16
-    Build the MS-Windows version with Python 2.6.5 and 3.1.2?
 Needs some work:
 -   Have a look at patch to enable screen access from Python. (Marko Mahnic,
     2010 Apr 12)
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -16,7 +16,7 @@ syn keyword vimTodo contained	COMBAK	FIX
 syn cluster vimCommentGroup	contains=vimTodo,@Spell
 
 " regular vim commands {{{2
-syn keyword vimCommand contained	abc[lear] argdo argu[ment] bel[owright] bN[ext] breakd[el] b[uffer] caddb[uffer] cb[uffer] cex[pr] cg[etfile] checkt[ime] cnew[er] col[der] con[tinue] cq[uit] delc[ommand] diffoff diffu[pdate] dr[op] echoe[rr] el[se] endfo[r] endw[hile] f[ile] fin[d] fo[ld] foldo[pen] gr[ep] his[tory] il[ist] iuna[bbrev] keepalt lad[dexpr] later lcl[ose] lf[ile] lg[etfile] ll lmapc[lear] lnf[ile] lockv[ar] lp[revious] lv[imgrep] ma[rk] mk[exrc] mkv[imrc] mz[scheme] new noh[lsearch] on[ly] ped[it] popu prev[ious] prof[ile] pta[g] ptn[ext] pts[elect] py[thon] r[ead] redr[aw] ret[ab] rightb[elow] rundo san[dbox] sbf[irst] sbN[ext] scripte[ncoding] setg[lobal] sh[ell] sla[st] sme sni[ff] sor[t] spelli[nfo] sp[lit] startg[replace] st[op] sunme syncbind tabd[o] tabl[ast] tabN[ext] tabs tcld[o] th[row] tm[enu] tp[revious] tu undoj[oin] uns[ilent] vert[ical] vi[sual] wa[ll] winp[os] wp[revious] ws[verb] xa[ll] xmenu xnoremenu
+syn keyword vimCommand contained	abc[lear] argdo argu[ment] bel[owright] bN[ext] breakd[el] b[uffer] caddb[uffer] cb[uffer] cex[pr] cg[etfile] checkt[ime] cnew[er] col[der] con[tinue] cq[uit] delc[ommand] diffoff diffu[pdate] dr[op] echoe[rr] el[se] endfo[r] endw[hile] f[ile] fin[d] fo[ld] foldo[pen] gr[ep] his[tory] il[ist] iuna[bbrev] keepalt lad[dexpr] later lcl[ose] lf[ile] lg[etfile] ll lmapc[lear] lnf[ile] lockv[ar] lp[revious] lv[imgrep] ma[rk] mk[exrc] mkv[imrc] mz[scheme] new noh[lsearch] on[ly] ped[it] popu prev[ious] prof[ile] pta[g] ptn[ext] pts[elect] py[thon] py3 r[ead] redr[aw] ret[ab] rightb[elow] rundo san[dbox] sbf[irst] sbN[ext] scripte[ncoding] setg[lobal] sh[ell] sla[st] sme sni[ff] sor[t] spelli[nfo] sp[lit] startg[replace] st[op] sunme syncbind tabd[o] tabl[ast] tabN[ext] tabs tcld[o] th[row] tm[enu] tp[revious] tu undoj[oin] uns[ilent] vert[ical] vi[sual] wa[ll] winp[os] wp[revious] ws[verb] xa[ll] xmenu xnoremenu
 syn keyword vimCommand contained	abo[veleft] arge[dit] as[cii] bf[irst] bo[tright] breakl[ist] buffers cad[dexpr] cc cf[ile] c[hange] cla[st] cn[ext] colo[rscheme] cope[n] cr[ewind] d[elete] diffpatch dig[raphs] ds[earch] echom[sg] elsei[f] endf[unction] ene[w] files fini[sh] foldc[lose] for grepa[dd] iabc[lear] imapc[lear] j[oin] keepj[umps] laddf[ile] lb[uffer] le[ft] lfir[st] lgr[ep] lla[st] lnew[er] lNf[ile] lol[der] lr[ewind] lvimgrepa[dd] marks mks[ession] mod[e] nbc[lose] n[ext] nu[mber] o[pen] pe[rl] popu[p] p[rint] promptf[ind] ptf[irst] ptN[ext] pu[t] qa[ll] rec[over] redraws[tatus] retu[rn] rub[y] ru[ntime] sa[rgument] sbl[ast] sbp[revious] scrip[tnames] setl[ocal] sign sl[eep] smenu sno[magic] so[urce] spellr[epall] spr[evious] star[tinsert] stopi[nsert] sunmenu t tabe[dit] tabm[ove] tabo[nly] ta[g] tclf[ile] tj[ump] tn[ext] tr[ewind] tu[nmenu] undol[ist] up[date] vie[w] vmapc[lear] wh[ile] win[size] wq wundo x[it] XMLent xunme
 syn keyword vimCommand contained	al[l] argg[lobal] bad[d] bl[ast] bp[revious] br[ewind] bun[load] caddf[ile] ccl[ose] cfir[st] changes cl[ist] cN[ext] comc[lear] co[py] cuna[bbrev] delf[unction] diffpu[t] di[splay] dsp[lit] echon em[enu] en[dif] ex filetype fir[st] folddoc[losed] fu[nction] ha[rdcopy] if is[earch] ju[mps] kee[pmarks] lan[guage] lc[d] lefta[bove] lgetb[uffer] lgrepa[dd] lli[st] lne[xt] lo[adview] lop[en] ls lw[indow] mat[ch] mksp[ell] m[ove] nb[key] N[ext] ol[dfiles] opt[ions] perld[o] pp[op] P[rint] promptr[epl] ptj[ump] ptp[revious] pw[d] q[uit] redi[r] reg[isters] rew[ind] rubyd[o] rv[iminfo] sav[eas] sbm[odified] sbr[ewind] se[t] sf[ind] sil[ent] sm[agic] sn[ext] snoreme spelld[ump] spellu[ndo] sre[wind] startr[eplace] sts[elect] sus[pend] tab tabf[ind] tabnew tabp[revious] tags te[aroff] tl[ast] tN[ext] try una[bbreviate] unh[ide] verb[ose] vim[grep] vne[w] winc[md] wn[ext] wqa[ll] wv[iminfo] xmapc[lear] XMLns xunmenu
 syn keyword vimCommand contained	arga[dd] argl[ocal] ba[ll] bm[odified] brea[k] bro[wse] bw[ipeout] cal[l] cd cgetb[uffer] chd[ir] clo[se] cnf[ile] comp[iler] cpf[ile] cw[indow] delm[arks] diffsplit dj[ump] earlier e[dit] emenu* endt[ry] exi[t] fina[lly] fix[del] foldd[oopen] go[to] hid[e] ij[ump] isp[lit] k laddb[uffer] la[st] lch[dir] lex[pr] lgete[xpr] l[ist] lmak[e] lN[ext] loc[kmarks] lpf[ile] lt[ag] mak[e] menut[ranslate] mkvie[w] mzf[ile] nbs[tart] nmapc[lear] omapc[lear] pc[lose] po[p] pre[serve] profd[el] ps[earch] ptl[ast] ptr[ewind] pyf[ile] quita[ll] red[o] res[ize] ri[ght] rubyf[ile] sal[l] sba[ll] sbn[ext] sb[uffer] setf[iletype] sfir[st] sim[alt] sm[ap] sN[ext] snoremenu spe[llgood] spellw[rong] sta[g] stj[ump] sun[hide] sv[iew] tabc[lose] tabfir[st] tabn[ext] tabr[ewind] tc[l] tf[irst] tm to[pleft] ts[elect] u[ndo] unlo[ckvar] ve[rsion] vimgrepa[dd] vs[plit] windo wN[ext] w[rite] X xme xnoreme y[ank]
@@ -594,16 +594,16 @@ if (g:vimsyn_embed =~ 'P' && has("python
  unlet! b:current_syntax
  exe "syn include @vimPythonScript ".s:pythonpath
  if exists("g:vimsyn_folding") && g:vimsyn_folding =~ 'P'
-  syn region vimPythonRegion fold matchgroup=vimScriptDelim start=+py\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+	contains=@vimPythonScript
-  syn region vimPythonRegion fold matchgroup=vimScriptDelim start=+py\%[thon]\s*<<\s*$+ end=+\.$+	contains=@vimPythonScript
+  syn region vimPythonRegion fold matchgroup=vimScriptDelim start=+py[3]\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+	contains=@vimPythonScript
+  syn region vimPythonRegion fold matchgroup=vimScriptDelim start=+py[3]\%[thon]\s*<<\s*$+ end=+\.$+	contains=@vimPythonScript
  else
-  syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+	contains=@vimPythonScript
-  syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]\s*<<\s*$+ end=+\.$+	contains=@vimPythonScript
+  syn region vimPythonRegion matchgroup=vimScriptDelim start=+py[3]\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+	contains=@vimPythonScript
+  syn region vimPythonRegion matchgroup=vimScriptDelim start=+py[3]\%[thon]\s*<<\s*$+ end=+\.$+	contains=@vimPythonScript
  endif
  syn cluster vimFuncBodyList	add=vimPythonRegion
 else
- syn region vimEmbedError start=+py\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+
- syn region vimEmbedError start=+py\%[thon]\s*<<\s*$+ end=+\.$+
+ syn region vimEmbedError start=+py[3]\%[thon]\s*<<\s*\z(.*\)$+ end=+^\z1$+
+ syn region vimEmbedError start=+py[3]\%[thon]\s*<<\s*$+ end=+\.$+
 endif
 unlet s:pythonpath
 
--- a/src/Make_bc5.mak
+++ b/src/Make_bc5.mak
@@ -44,6 +44,9 @@
 # PYTHON	define to path to Python dir to get PYTHON support (not defined)
 #   PYTHON_VER	    define to version of Python being used (22)
 #   DYNAMIC_PYTHON  no or yes: use yes to load the Python DLL dynamically (no)
+# PYTHON3	define to path to Python3 dir to get PYTHON3 support (not defined)
+#   PYTHON3_VER	    define to version of Python3 being used (31)
+#   DYNAMIC_PYTHON3  no or yes: use yes to load the Python3 DLL dynamically (no)
 # TCL		define to path to TCL dir to get TCL support (not defined)
 #   TCL_VER	define to version of TCL being used (83)
 #   DYNAMIC_TCL no or yes: use yes to load the TCL DLL dynamically (no)
@@ -141,6 +144,9 @@ NETBEANS = yes
 ### PYTHON: uncomment this line if you want python support in vim
 # PYTHON=c:\python22
 
+### PYTHON3: uncomment this line if you want python3 support in vim
+# PYTHON3=c:\python31
+
 ### RUBY: uncomment this line if you want ruby support in vim
 # RUBY=c:\ruby
 
@@ -207,6 +213,7 @@ ALIGN = 4
 !if ("$(FASTCALL)"=="") && \
 	("$(LUA)"=="") && \
 	("$(PYTHON)"=="") && \
+	("$(PYTHON3)"=="") && \
 	("$(PERL)"=="") && \
 	("$(TCL)"=="") && \
 	("$(RUBY)"=="") && \
@@ -328,8 +335,14 @@ PERL_LIB_FLAG = /nodefaultlib:
 !endif
 
 !ifdef PYTHON
+!ifdef PYTHON3
+DYNAMIC_PYTHON=yes
+DYNAMIC_PYTHON3=yes
+!endif
+!endif
+
+!ifdef PYTHON
 INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_PYTHON
-INCLUDE = $(PYTHON)\include;$(INCLUDE)
 !ifndef PYTHON_VER
 PYTHON_VER = 22
 !endif
@@ -339,6 +352,18 @@ PYTHON_LIB_FLAG = /nodefaultlib:
 !endif
 !endif
 
+!ifdef PYTHON3
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_PYTHON3
+!ifndef PYTHON3_VER
+PYTHON3_VER = 31
+!endif
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_PYTHON3 -DDYNAMIC_PYTHON3_DLL=\"python$(PYTHON3_VER).dll\"
+PYTHON3_LIB_FLAG = /nodefaultlib:
+!endif
+!endif
+
+
 !ifdef RUBY
 !ifndef RUBY_VER
 RUBY_VER = 16
@@ -618,6 +643,11 @@ vimobj = $(vimobj) \
     $(OBJDIR)\if_python.obj
 !endif
 
+!ifdef PYTHON3
+vimobj = $(vimobj) \
+    $(OBJDIR)\if_python3.obj
+!endif
+
 !ifdef RUBY
 vimobj = $(vimobj) \
     $(OBJDIR)\if_ruby.obj
@@ -734,6 +764,12 @@ MSG = $(MSG) PYTHON
 MSG = $(MSG)(dynamic)
 ! endif
 !endif
+!ifdef PYTHON3
+MSG = $(MSG) PYTHON3
+! if "$(DYNAMIC_PYTHON3)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
 !ifdef RUBY
 MSG = $(MSG) RUBY
 ! if "$(DYNAMIC_RUBY)" == "yes"
@@ -827,6 +863,9 @@ clean:
 !ifdef PYTHON
 	-@del python.lib
 !endif
+!ifdef PYTHON3
+	-@del python3.lib
+!endif
 !ifdef RUBY
 	-@del ruby.lib
 !endif
@@ -867,6 +906,9 @@ clean:
 !ifdef PYTHON
 	$(PYTHON_LIB_FLAG)python.lib+
 !endif
+!ifdef PYTHON3
+	$(PYTHON3_LIB_FLAG)python3.lib+
+!endif
 !ifdef RUBY
 	$(RUBY_LIB_FLAG)ruby.lib+
 !endif
@@ -919,6 +961,9 @@ clean:
 !ifdef PYTHON
 	$(PYTHON_LIB_FLAG)python.lib+
 !endif
+!ifdef PYTHON3
+	$(PYTHON3_LIB_FLAG)python3.lib+
+!endif
 !ifdef RUBY
 	$(RUBY_LIB_FLAG)ruby.lib+
 !endif
@@ -962,7 +1007,10 @@ if_perl.c: if_perl.xs typemap
 	    $(PERL)\lib\ExtUtils\typemap if_perl.xs > $@
 
 $(OBJDIR)\if_python.obj: if_python.c python.lib
-	$(CC) $(CCARG) $(CC1) $(CC2)$@ -pc if_python.c
+	$(CC) -I$(PYTHON)\include $(CCARG) $(CC1) $(CC2)$@ -pc if_python.c
+
+$(OBJDIR)\if_python3.obj: if_python3.c python3.lib
+	$(CC) -I$(PYTHON3)\include $(CCARG) $(CC1) $(CC2)$@ -pc if_python3.c
 
 $(OBJDIR)\if_ruby.obj: if_ruby.c ruby.lib
 	$(CC) $(CCARG) $(CC1) $(CC2)$@ -pc if_ruby.c
@@ -1017,6 +1065,9 @@ perl.lib: $(PERL)\lib\CORE\perl$(PERL_VE
 python.lib: $(PYTHON)\libs\python$(PYTHON_VER).lib
 	coff2omf $(PYTHON)\libs\python$(PYTHON_VER).lib $@
 
+python3.lib: $(PYTHON3)\libs\python$(PYTHON3_VER).lib
+	coff2omf $(PYTHON3)\libs\python$(PYTHON3_VER).lib $@
+
 ruby.lib: $(RUBY)\lib\$(RUBY_INSTALL_NAME).lib
 	coff2omf $(RUBY)\lib\$(RUBY_INSTALL_NAME).lib $@
 
@@ -1065,3 +1116,4 @@ vimrun.exe: vimrun.c
 | $@
 
 # vi:set sts=4 sw=4:
+
--- a/src/Make_cyg.mak
+++ b/src/Make_cyg.mak
@@ -14,6 +14,9 @@
 # PYTHON	define to path to Python dir to get PYTHON support (not defined)
 #   PYTHON_VER	    define to version of Python being used (22)
 #   DYNAMIC_PYTHON  no or yes: use yes to load the Python DLL dynamically (yes)
+# PYTHON3	define to path to Python3 dir to get PYTHON3 support (not defined)
+#   PYTHON3_VER	    define to version of Python3 being used (22)
+#   DYNAMIC_PYTHON3  no or yes: use yes to load the Python3 DLL dynamically (yes)
 # TCL		define to path to TCL dir to get TCL support (not defined)
 #   TCL_VER	define to version of TCL being used (83)
 #   DYNAMIC_TCL no or yes: use yes to load the TCL DLL dynamically (yes)
@@ -139,7 +142,6 @@ endif
 ##############################
 ifdef PYTHON
 DEFINES += -DFEAT_PYTHON
-INCLUDES += -I$(PYTHON)/include
 EXTRA_OBJS += $(OUTDIR)/if_python.o
 
 ifndef DYNAMIC_PYTHON
@@ -158,6 +160,29 @@ endif
 endif
 
 ##############################
+# DYNAMIC_PYTHON3=yes works.
+# DYNAMIC_PYTHON3=no does not (unresolved externals on link).
+##############################
+ifdef PYTHON3
+DEFINES += -DFEAT_PYTHON3
+EXTRA_OBJS += $(OUTDIR)/if_python3.o
+
+ifndef DYNAMIC_PYTHON3
+DYNAMIC_PYTHON3 = yes
+endif
+
+ifndef PYTHON3_VER
+PYTHON3_VER = 31
+endif
+
+ifeq (yes, $(DYNAMIC_PYTHON3))
+DEFINES += -DDYNAMIC_PYTHON3 -DDYNAMIC_PYTHON3_DLL=\"python$(PYTHON3_VER).dll\"
+else
+EXTRA_LIBS += $(PYTHON3)/libs/python$(PYTHON3_VER).lib
+endif
+endif
+
+##############################
 # DYNAMIC_RUBY=yes works.
 # DYNAMIC_RUBY=no does not (process exits).
 ##############################
@@ -563,6 +588,12 @@ distclean: clean
 $(OUTDIR)/if_ole.o:	if_ole.cpp $(INCL)
 	$(CC) -c $(CFLAGS) if_ole.cpp -o $(OUTDIR)/if_ole.o
 
+$(OUTDIR)/if_python.o : if_python.c $(INCL)
+	$(CC) -c $(CFLAGS) -I$(PYTHON)/include $< -o $@
+
+$(OUTDIR)/if_python3.o : if_python3.c $(INCL)
+	$(CC) -c $(CFLAGS) -I$(PYTHON3)/include $< -o $@
+
 if_perl.c: if_perl.xs typemap
 	$(PERL)/bin/perl `cygpath -d $(PERL)/lib/ExtUtils/xsubpp` \
 		-prototypes -typemap \
@@ -612,3 +643,4 @@ else
 	@echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> pathdef.c
 	@echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> pathdef.c
 endif
+
--- a/src/Make_ming.mak
+++ b/src/Make_ming.mak
@@ -194,6 +194,28 @@ PYTHONINC=-I $(PYTHON)/win32inc
 endif
 endif
 
+#PYTHON3: See comment for Python 2 above
+
+ifdef PYTHON3
+ifndef DYNAMIC_PYTHON3
+DYNAMIC_PYTHON3=yes
+endif
+
+ifndef PYTHON3_VER
+PYTHON3_VER=31
+endif
+
+ifeq (no,$(DYNAMIC_PYTHON3))
+PYTHON3LIB=-L$(PYTHON3)/libs -lPYTHON$(PYTHON3_VER)
+endif
+
+ifeq ($(CROSS),no)
+PYTHON3INC=-I $(PYTHON3)/include
+else
+PYTHON3INC=-I $(PYTHON3)/win32inc
+endif
+endif
+
 #	TCL interface:
 #	  TCL=[Path to TCL directory]
 #	  DYNAMIC_TCL=yes (to load the TCL DLL dynamically)
@@ -334,9 +356,16 @@ endif
 endif
 
 ifdef PYTHON
-CFLAGS += -DFEAT_PYTHON $(PYTHONINC)
+CFLAGS += -DFEAT_PYTHON 
 ifeq (yes, $(DYNAMIC_PYTHON))
-CFLAGS += -DDYNAMIC_PYTHON -DDYNAMIC_PYTHON_DLL=\"python$(PYTHON_VER).dll\"
+CFLAGS += -DDYNAMIC_PYTHON
+endif
+endif
+
+ifdef PYTHON3 
+CFLAGS += -DFEAT_PYTHON3 
+ifeq (yes, $(DYNAMIC_PYTHON3))
+CFLAGS += -DDYNAMIC_PYTHON3 
 endif
 endif
 
@@ -468,6 +497,9 @@ endif
 ifdef PYTHON
 OBJ += $(OUTDIR)/if_python.o
 endif
+ifdef PYTHON3
+OBJ += $(OUTDIR)/if_python3.o
+endif
 ifdef RUBY
 OBJ += $(OUTDIR)/if_ruby.o
 endif
@@ -576,7 +608,7 @@ uninstal.exe: uninstal.c
 	$(CC) $(CFLAGS) -o uninstal.exe uninstal.c $(LIB)
 
 $(TARGET): $(OUTDIR) $(OBJ)
-	$(CC) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(RUBYLIB)
+	$(CC) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)
 
 upx: exes
 	upx gvim.exe
@@ -608,6 +640,12 @@ INCL = vim.h feature.h os_win32.h os_dos
 	structs.h regexp.h option.h ex_cmds.h proto.h globals.h farsi.h \
 	gui.h
 
+$(OUTDIR)/if_python.o : if_python.c $(INCL)
+	$(CC) -c $(CFLAGS) $(PYTHONINC) -DDYNAMIC_PYTHON_DLL=\"python$(PYTHON_VER).dll\" $< -o $@
+
+$(OUTDIR)/if_python3.o : if_python3.c $(INCL)
+	$(CC) -c $(CFLAGS) $(PYTHON3INC) -DDYNAMIC_PYTHON3_DLL=\"PYTHON$(PYTHON3_VER).dll\" $< -o $@
+
 $(OUTDIR)/%.o : %.c $(INCL)
 	$(CC) -c $(CFLAGS) $< -o $@
 
@@ -659,7 +697,7 @@ ifneq (sh.exe, $(SHELL))
 	@echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' >> pathdef.c
 	@echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' >> pathdef.c
 	@echo 'char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)";' >> pathdef.c
-	@echo 'char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(RUBYLIB)";' >> pathdef.c
+	@echo 'char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)";' >> pathdef.c
 	@echo 'char_u *compiled_user = (char_u *)"$(USERNAME)";' >> pathdef.c
 	@echo 'char_u *compiled_sys = (char_u *)"$(USERDOMAIN)";' >> pathdef.c
 else
@@ -669,7 +707,7 @@ else
 	@echo char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)"; >> pathdef.c
 	@echo char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)"; >> pathdef.c
 	@echo char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)"; >> pathdef.c
-	@echo char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(RUBYLIB)"; >> pathdef.c
+	@echo char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)"; >> pathdef.c
 	@echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> pathdef.c
 	@echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> pathdef.c
 endif
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -52,6 +52,11 @@
 #	  DYNAMIC_PYTHON=yes (to load the Python DLL dynamically)
 #	  PYTHON_VER=[Python version, eg 15, 20]  (default is 22)
 #
+#	Python3 interface:
+#	  PYTHON3=[Path to Python3 directory]
+#	  DYNAMIC_PYTHON3=yes (to load the Python3 DLL dynamically)
+#	  PYTHON3_VER=[Python3 version, eg 30, 31]  (default is 31)
+#
 #	Ruby interface:
 #	  RUBY=[Path to Ruby directory]
 #	  DYNAMIC_RUBY=yes (to load the Ruby DLL dynamically)
@@ -166,6 +171,9 @@ OBJDIR = $(OBJDIR)L
 !ifdef PYTHON
 OBJDIR = $(OBJDIR)Y
 !endif
+!ifdef PYTHON3
+OBJDIR = $(OBJDIR)H
+!endif
 !ifdef TCL
 OBJDIR = $(OBJDIR)T
 !endif
@@ -641,6 +649,13 @@ LUA_LIB = "$(LUA)\lib\lua$(LUA_VER).lib"
 !endif
 !endif
 
+!ifdef PYTHON
+!ifdef PYTHON3
+DYNAMIC_PYTHON=yes
+DYNAMIC_PYTHON3=yes
+!endif
+!endif
+
 # PYTHON interface
 !ifdef PYTHON
 !ifndef PYTHON_VER
@@ -662,6 +677,27 @@ PYTHON_LIB = $(PYTHON)\libs\python$(PYTH
 !endif
 !endif
 
+# PYTHON3 interface
+!ifdef PYTHON3
+!ifndef PYTHON3_VER
+PYTHON3_VER = 31
+!endif
+!message Python3 requested (version $(PYTHON3_VER)) - root dir is "$(PYTHON3)"
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+!message Python3 DLL will be loaded dynamically
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_PYTHON3
+PYTHON3_OBJ = $(OUTDIR)\if_python3.obj
+PYTHON3_INC = /I "$(PYTHON3)\Include" /I "$(PYTHON3)\PC"
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3 \
+		-DDYNAMIC_PYTHON3_DLL=\"python$(PYTHON3_VER).dll\"
+PYTHON3_LIB = /nodefaultlib:python$(PYTHON3_VER).lib
+!else
+PYTHON3_LIB = $(PYTHON3)\libs\python$(PYTHON3_VER).lib
+!endif
+!endif
+
 # MzScheme interface
 !ifdef MZSCHEME
 !message MzScheme requested - root dir is "$(MZSCHEME)"
@@ -835,7 +871,7 @@ conflags = $(conflags) /map /mapinfo:lin
 
 LINKARGS1 = $(linkdebug) $(conflags)
 LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(LIBC) $(OLE_LIB)  user32.lib $(SNIFF_LIB) \
-		$(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(RUBY_LIB) \
+		$(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(PYTHON3_LIB) $(RUBY_LIB) \
 		$(TCL_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
 
 # Report link time code generation progress if used. 
@@ -851,12 +887,12 @@ all:	$(VIM).exe vimrun.exe install.exe u
 		GvimExt/gvimext.dll
 
 $(VIM).exe: $(OUTDIR) $(OBJ) $(GUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
-		$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
+		$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
 		$(SNIFF_OBJ) $(CSCOPE_OBJ) $(NETBEANS_OBJ) $(XPM_OBJ) \
 		version.c version.h
 	$(CC) $(CFLAGS) version.c
 	$(link) $(LINKARGS1) -out:$(VIM).exe $(OBJ) $(GUI_OBJ) $(OLE_OBJ) \
-		$(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(RUBY_OBJ) \
+		$(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) \
 		$(TCL_OBJ) $(SNIFF_OBJ) $(CSCOPE_OBJ) $(NETBEANS_OBJ) \
 		$(XPM_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
 
@@ -1016,6 +1052,9 @@ mzscheme_base.c:
 $(OUTDIR)/if_python.obj: $(OUTDIR) if_python.c  $(INCL)
 	$(CC) $(CFLAGS) $(PYTHON_INC) if_python.c
 
+$(OUTDIR)/if_python3.obj: $(OUTDIR) if_python3.c  $(INCL)
+	$(CC) $(CFLAGS) $(PYTHON3_INC) if_python3.c
+
 $(OUTDIR)/if_ole.obj: $(OUTDIR) if_ole.cpp  $(INCL) if_ole.h
 
 $(OUTDIR)/if_ruby.obj: $(OUTDIR) if_ruby.c  $(INCL)
--- a/src/Makefile
+++ b/src/Makefile
@@ -41,6 +41,7 @@
 #		--enable-luainterp	for Lua interpreter
 #		--enable-perlinterp	for Perl interpreter
 #		--enable-pythoninterp	for Python interpreter
+#		--enable-python3interp	for Python3 interpreter
 #		--enable-rubyinterp	for Ruby interpreter
 #		--enable-tclinterp	for Tcl interpreter
 #		--enable-cscope		for Cscope interface
@@ -383,7 +384,12 @@ CClink = $(CC)
 # NOTE: This may cause threading to be enabled, which has side effects (such
 # as using different libraries and debugging becomes more difficult).
 # NOTE: Using this together with Perl may cause a crash in initialization.
+# For Python3 support make a symbolic link in /usr/local/bin: 
+#	ln -s python3 python3.1
+# If both python2.x and python3.x are enabled then the linking will be via
+# dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available
 #CONF_OPT_PYTHON = --enable-pythoninterp
+#CONF_OPT_PYTHON3 = --enable-python3interp
 
 # TCL
 # Uncomment this when you want to include the Tcl interface.
@@ -1304,7 +1310,7 @@ SHELL = /bin/sh
 .SUFFIXES: .c .o .pro
 
 PRE_DEFS = -Iproto $(DEFS) $(GUI_DEFS) $(GUI_IPATH) $(CPPFLAGS) $(EXTRA_IPATHS)
-POST_DEFS = $(X_CFLAGS) $(LUA_CFLAGS) $(MZSCHEME_CFLAGS) $(PERL_CFLAGS) $(ECL_CFLAGS) $(PYTHON_CFLAGS) $(TCL_CFLAGS) $(RUBY_CFLAGS) $(EXTRA_DEFS)
+POST_DEFS = $(X_CFLAGS) $(LUA_CFLAGS) $(MZSCHEME_CFLAGS) $(PERL_CFLAGS) $(ECL_CFLAGS) $(TCL_CFLAGS) $(RUBY_CFLAGS) $(EXTRA_DEFS)
 
 ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PROFILE_CFLAGS) $(POST_DEFS)
 
@@ -1319,7 +1325,23 @@ LINT_EXTRA = -DUSE_SNIFF -DHANGUL_INPUT 
 DEPEND_CFLAGS = -DPROTO -DDEPEND -DFEAT_GUI $(LINT_CFLAGS)
 
 ALL_LIB_DIRS = $(GUI_LIBS_DIR) $(X_LIBS_DIR)
-ALL_LIBS = $(GUI_LIBS1) $(GUI_X_LIBS) $(GUI_LIBS2) $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIBS) $(LIBS) $(EXTRA_LIBS) $(LUA_LIBS) $(MZSCHEME_LIBS) $(PERL_LIBS) $(PYTHON_LIBS) $(TCL_LIBS) $(RUBY_LIBS) $(PROFILE_LIBS)
+ALL_LIBS = \
+	   $(GUI_LIBS1) \
+	   $(GUI_X_LIBS) \
+	   $(GUI_LIBS2) \
+	   $(X_PRE_LIBS) \
+	   $(X_LIBS) \
+	   $(X_EXTRA_LIBS) \
+	   $(LIBS) \
+	   $(EXTRA_LIBS) \
+	   $(LUA_LIBS) \
+	   $(MZSCHEME_LIBS) \
+	   $(PERL_LIBS) \
+	   $(PYTHON_LIBS) \
+	   $(PYTHON3_LIBS) \
+	   $(TCL_LIBS) \
+	   $(RUBY_LIBS) \
+	   $(PROFILE_LIBS)
 
 # abbreviations
 DEST_BIN = $(DESTDIR)$(BINDIR)
@@ -1422,15 +1444,24 @@ BASIC_SRC = \
 	window.c \
 	$(OS_EXTRA_SRC)
 
-SRC =	$(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) $(LUA_SRC) $(MZSCHEME_SRC) \
-	$(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) $(RUBY_SRC) \
-	$(SNIFF_SRC) $(WORKSHOP_SRC) $(WSDEBUG_SRC)
+SRC =	$(BASIC_SRC) \
+	$(GUI_SRC) \
+	$(HANGULIN_SRC) \
+	$(LUA_SRC) \
+	$(MZSCHEME_SRC) \
+	$(PERL_SRC) \
+	$(PYTHON_SRC) $(PYTHON3_SRC) \
+	$(TCL_SRC) \
+	$(RUBY_SRC) \
+	$(SNIFF_SRC) \
+	$(WORKSHOP_SRC) \
+	$(WSDEBUG_SRC)
 
 TAGS_SRC = *.c *.cpp if_perl.xs
 
 EXTRA_SRC = hangulin.c if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \
-	    if_python.c if_tcl.c if_ruby.c if_sniff.c gui_beval.c \
-	    workshop.c wsdebug.c integration.c netbeans.c
+	    if_python.c if_python3.c if_tcl.c if_ruby.c if_sniff.c \
+	    gui_beval.c workshop.c wsdebug.c integration.c netbeans.c
 
 # All sources, also the ones that are not configured
 ALL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(EXTRA_SRC)
@@ -1438,7 +1469,7 @@ ALL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(
 # Which files to check with lint.  Select one of these three lines.  ALL_SRC
 # checks more, but may not work well for checking a GUI that wasn't configured.
 # The perl sources also don't work well with lint.
-LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) $(PYTHON_SRC) $(TCL_SRC) \
+LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) $(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \
 	$(SNIFF_SRC) $(WORKSHOP_SRC) $(WSDEBUG_SRC) $(NETBEANS_SRC)
 #LINT_SRC = $(SRC)
 #LINT_SRC = $(ALL_SRC)
@@ -1499,6 +1530,7 @@ OBJ = \
 	$(MZSCHEME_OBJ) \
 	$(PERL_OBJ) \
 	$(PYTHON_OBJ) \
+	$(PYTHON3_OBJ) \
 	$(TCL_OBJ) \
 	$(RUBY_OBJ) \
 	$(OS_EXTRA_OBJ) \
@@ -1528,6 +1560,7 @@ PRO_AUTO = \
 	if_cscope.pro \
 	if_xcmdsrv.pro \
 	if_python.pro \
+	if_python3.pro \
 	if_ruby.pro \
 	main.pro \
 	mark.pro \
@@ -1589,7 +1622,7 @@ config auto/config.mk: auto/configure co
 		CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \
 		LDFLAGS="$(LDFLAGS)" $(CONF_SHELL) srcdir="$(srcdir)" \
 		./configure $(CONF_OPT_GUI) $(CONF_OPT_X) $(CONF_OPT_XSMP) \
-		$(CONF_OPT_DARWIN) $(CONF_OPT_PERL) $(CONF_OPT_PYTHON) \
+		$(CONF_OPT_DARWIN) $(CONF_OPT_PERL) $(CONF_OPT_PYTHON) $(CONF_OPT_PYTHON3) \
 		$(CONF_OPT_TCL) $(CONF_OPT_RUBY) $(CONF_OPT_NLS) \
 		$(CONF_OPT_CSCOPE) $(CONF_OPT_MULTIBYTE) $(CONF_OPT_INPUT) \
 		$(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) $(CONF_OPT_WORKSHOP) \
@@ -2464,8 +2497,24 @@ objects/if_perl.o: auto/if_perl.c
 objects/if_perlsfio.o: if_perlsfio.c
 	$(CCC) -o $@ if_perlsfio.c
 
-objects/if_python.o: if_python.c
-	$(CCC) -o $@ $(PYTHON_CFLAGS_EXTRA) if_python.c
+objects/py_config.o: $(PYTHON_CONFDIR)/config.c
+	$(CCC) $(PYTHON_CFLAGS) -o $@ $(PYTHON_CONFDIR)/config.c \
+		-I$(PYTHON_CONFDIR) -DHAVE_CONFIG_H -DNO_MAIN
+
+objects/py_getpath.o: $(PYTHON_CONFDIR)/getpath.c
+	$(CCC) $(PYTHON_CFLAGS) -o $@ $(PYTHON_CONFDIR)/getpath.c \
+		-I$(PYTHON_CONFDIR) -DHAVE_CONFIG_H -DNO_MAIN \
+		$(PYTHON_GETPATH_CFLAGS)
+
+objects/py3_config.o: $(PYTHON3_CONFDIR)/config.c
+	$(CCC) $(PYTHON3_CFLAGS) -o $@ $(PYTHON3_CONFDIR)/config.c \
+		-I$(PYTHON3_CONFDIR) -DHAVE_CONFIG_H -DNO_MAIN
+
+objects/if_python.o: if_python.c 
+	$(CCC) $(PYTHON_CFLAGS) $(PYTHON_CFLAGS_EXTRA) -o $@ if_python.c
+
+objects/if_python3.o: if_python3.c 
+	$(CCC) $(PYTHON3_CFLAGS) $(PYTHON3_CFLAGS_EXTRA) -o $@ if_python3.c
 
 objects/if_ruby.o: if_ruby.c
 	$(CCC) -o $@ if_ruby.c
@@ -2536,15 +2585,6 @@ objects/os_unix.o: os_unix.c
 objects/pathdef.o: auto/pathdef.c
 	$(CCC) -o $@ auto/pathdef.c
 
-objects/py_config.o: $(PYTHON_CONFDIR)/config.c
-	$(CCC) -o $@ $(PYTHON_CONFDIR)/config.c \
-		-I$(PYTHON_CONFDIR) -DHAVE_CONFIG_H -DNO_MAIN
-
-objects/py_getpath.o: $(PYTHON_CONFDIR)/getpath.c
-	$(CCC) -o $@ $(PYTHON_CONFDIR)/getpath.c \
-		-I$(PYTHON_CONFDIR) -DHAVE_CONFIG_H -DNO_MAIN \
-		$(PYTHON_GETPATH_CFLAGS)
-
 objects/pty.o: pty.c
 	$(CCC) -o $@ pty.c
 
@@ -2978,6 +3018,10 @@ objects/if_python.o: if_python.c vim.h a
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
  regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
  globals.h farsi.h arabic.h
+objects/if_python3.o: if_python3.c vim.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
 objects/if_tcl.o: if_tcl.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
  gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -639,6 +639,12 @@ TCL_PRO
 TCL_OBJ
 TCL_SRC
 vi_cv_path_tcl
+PYTHON3_OBJ
+PYTHON3_SRC
+PYTHON3_CFLAGS
+PYTHON3_LIBS
+PYTHON3_CONFDIR
+vi_cv_path_python3
 PYTHON_OBJ
 PYTHON_SRC
 PYTHON_CFLAGS
@@ -755,6 +761,8 @@ with_plthome
 enable_perlinterp
 enable_pythoninterp
 with_python_config_dir
+enable_python3interp
+with_python3_config_dir
 enable_tclinterp
 with_tclsh
 enable_rubyinterp
@@ -1417,6 +1425,7 @@ Optional Features:
   --enable-mzschemeinterp   Include MzScheme interpreter.
   --enable-perlinterp     Include Perl interpreter.
   --enable-pythoninterp   Include Python interpreter.
+  --enable-python3interp   Include Python3 interpreter.
   --enable-tclinterp      Include Tcl interpreter.
   --enable-rubyinterp     Include Ruby interpreter.
   --enable-cscope         Include cscope interface.
@@ -1458,6 +1467,7 @@ Optional Packages:
   --with-lua-prefix=PFX   Prefix where Lua is installed.
   --with-plthome=PLTHOME   Use PLTHOME.
   --with-python-config-dir=PATH  Python's config directory
+  --with-python3-config-dir=PATH  Python's config directory
   --with-tclsh=PATH       which tclsh to use (default: tclsh8.0)
   --with-ruby-command=RUBY  name of the Ruby command (default: ruby)
   --with-x                use the X Window System
@@ -5362,6 +5372,286 @@ fi
 
 
 
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-python3interp argument" >&5
+$as_echo_n "checking --enable-python3interp argument... " >&6; }
+# Check whether --enable-python3interp was given.
+if test "${enable_python3interp+set}" = set; then :
+  enableval=$enable_python3interp;
+else
+  enable_python3interp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_python3interp" >&5
+$as_echo "$enable_python3interp" >&6; }
+if test "$enable_python3interp" = "yes"; then
+    # Extract the first word of "python3", so it can be a program name with args.
+set dummy python3; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_vi_cv_path_python3+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $vi_cv_path_python3 in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_vi_cv_path_python3="$vi_cv_path_python3" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_vi_cv_path_python3="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+vi_cv_path_python3=$ac_cv_path_vi_cv_path_python3
+if test -n "$vi_cv_path_python3"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3" >&5
+$as_echo "$vi_cv_path_python3" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  if test "X$vi_cv_path_python3" != "X"; then
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python version" >&5
+$as_echo_n "checking Python version... " >&6; }
+if test "${vi_cv_var_python3_version+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  vi_cv_var_python3_version=`
+          ${vi_cv_path_python3} -c 'import sys; print(sys.version[1:3])'`
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python3_version" >&5
+$as_echo "$vi_cv_var_python3_version" >&6; }
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's install prefix" >&5
+$as_echo_n "checking Python's install prefix... " >&6; }
+if test "${vi_cv_path_python3_pfx+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+   vi_cv_path_python3_pfx=`
+     ${vi_cv_path_python3} -c \
+     "import sys; print(sys.prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_pfx" >&5
+$as_echo "$vi_cv_path_python3_pfx" >&6; }
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's execution prefix" >&5
+$as_echo_n "checking Python's execution prefix... " >&6; }
+if test "${vi_cv_path_python3_epfx+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+   vi_cv_path_python3_epfx=`
+     ${vi_cv_path_python3} -c \
+     "import sys; print(sys.exec_prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_epfx" >&5
+$as_echo "$vi_cv_path_python3_epfx" >&6; }
+
+
+    if test "${vi_cv_path_python3path+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+   vi_cv_path_python3path=`
+     unset PYTHONPATH;
+     ${vi_cv_path_python3} -c \
+     "import sys, string; print(':'.join(sys.path))"`
+fi
+
+
+
+
+# Check whether --with-python3-config-dir was given.
+if test "${with_python3_config_dir+set}" = set; then :
+  withval=$with_python3_config_dir;  vi_cv_path_python3_conf="${withval}"
+fi
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's configuration directory" >&5
+$as_echo_n "checking Python's configuration directory... " >&6; }
+if test "${vi_cv_path_python3_conf+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+     vi_cv_path_python3_conf=
+     for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do
+       for subdir in lib share; do
+         d="${path}/${subdir}/python3${vi_cv_var_python3_version}/config"
+         if test -d "$d" && test -f "$d/config.c"; then
+           vi_cv_path_python3_conf="$d"
+         fi
+       done
+     done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_conf" >&5
+$as_echo "$vi_cv_path_python3_conf" >&6; }
+
+    PYTHON3_CONFDIR="${vi_cv_path_python3_conf}"
+
+    if test "X$PYTHON3_CONFDIR" = "X"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't find it!" >&5
+$as_echo "can't find it!" >&6; }
+    else
+
+                  if test "${vi_cv_path_python3_plibs+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+          pwd=`pwd`
+          tmp_mkf="$pwd/config-PyMake$$"
+          cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+	@echo "python3_MODLIBS='$(MODLIBS)'"
+	@echo "python3_LIBS='$(LIBS)'"
+	@echo "python3_SYSLIBS='$(SYSLIBS)'"
+	@echo "python3_LINKFORSHARED='$(LINKFORSHARED)'"
+eof
+                    eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+          rm -f -- "${tmp_mkf}"
+          vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython3${vi_cv_var_python3_version}"
+          vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_MODLIBS} ${python3_LIBS} ${python3_SYSLIBS} ${python3_LINKFORSHARED}"
+                    vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//`
+          vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//`
+
+fi
+
+
+      PYTHON3_LIBS="${vi_cv_path_python3_plibs}"
+      if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then
+        PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python3${vi_cv_var_python3_version}"
+      else
+        PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python3${vi_cv_var_python3_version} -I${vi_cv_path_python3_epfx}/include/python3${vi_cv_var_python3_version}"
+      fi
+      PYTHON3_SRC="if_python3.c"
+            if test "x$MACOSX" = "xyes"; then
+        PYTHON3_OBJ="objects/if_python3.o"
+      else
+        PYTHON3_OBJ="objects/if_python3.o objects/py3_config.o"
+      fi
+
+                                                { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread should be used" >&5
+$as_echo_n "checking if -pthread should be used... " >&6; }
+      threadsafe_flag=
+      thread_lib=
+            if test "`(uname) 2>/dev/null`" != Darwin; then
+        test "$GCC" = yes && threadsafe_flag="-pthread"
+        if test "`(uname) 2>/dev/null`" = FreeBSD; then
+          threadsafe_flag="-D_THREAD_SAFE"
+          thread_lib="-pthread"
+        fi
+      fi
+      libs_save_old=$LIBS
+      if test -n "$threadsafe_flag"; then
+        cflags_save=$CFLAGS
+        CFLAGS="$CFLAGS $threadsafe_flag"
+        LIBS="$LIBS $thread_lib"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; LIBS=$libs_save_old
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        CFLAGS=$cflags_save
+      else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+      fi
+
+                  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Python are sane" >&5
+$as_echo_n "checking if compile and link flags for Python are sane... " >&6; }
+      cflags_save=$CFLAGS
+      libs_save=$LIBS
+      CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+      LIBS="$LIBS $PYTHON3_LIBS"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; python3_ok=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PYTHON3 DISABLED" >&5
+$as_echo "no: PYTHON3 DISABLED" >&6; }; python3_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+      CFLAGS=$cflags_save
+      LIBS=$libs_save
+      if test "$python3_ok" = yes; then
+        $as_echo "#define FEAT_PYTHON3 1" >>confdefs.h
+
+      else
+        LIBS=$libs_save_old
+        PYTHON3_SRC=
+        PYTHON3_OBJ=
+        PYTHON3_LIBS=
+        PYTHON3_CFLAGS=
+      fi
+    fi
+  fi
+fi
+
+
+
+
+
+
+
+if test "$python_ok" = yes && test "$python3_ok" = yes; then
+  $as_echo "#define DYNAMIC_PYTHON 1" >>confdefs.h
+
+  $as_echo "#define DYNAMIC_PYTHON3 1" >>confdefs.h
+
+  PYTHON_SRC="if_python.c"
+  PYTHON_OBJ="objects/if_python.o"
+  PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"libpython${vi_cv_var_python_version}.so\\\""
+  PYTHON_LIBS=
+  PYTHON3_SRC="if_python3.c"
+  PYTHON3_OBJ="objects/if_python3.o"
+  PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"libpython3${vi_cv_var_python3_version}.so\\\""
+  PYTHON3_LIBS=
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-tclinterp argument" >&5
 $as_echo_n "checking --enable-tclinterp argument... " >&6; }
 # Check whether --enable-tclinterp was given.
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -607,6 +607,9 @@ free_buffer(buf)
 #ifdef FEAT_PYTHON
     python_buffer_free(buf);
 #endif
+#ifdef FEAT_PYTHON3
+    python3_buffer_free(buf);
+#endif
 #ifdef FEAT_RUBY
     ruby_buffer_free(buf);
 #endif
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -328,6 +328,15 @@
 /* Define if you want to include the Python interpreter. */
 #undef FEAT_PYTHON
 
+/* Define if you want to include the Python3 interpreter. */
+#undef FEAT_PYTHON3
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_PYTHON
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_PYTHON3
+
 /* Define if you want to include the Ruby interpreter. */
 #undef FEAT_RUBY
 
--- a/src/config.mk.in
+++ b/src/config.mk.in
@@ -66,6 +66,12 @@ PYTHON_LIBS	= @PYTHON_LIBS@
 PYTHON_CONFDIR	= @PYTHON_CONFDIR@
 PYTHON_GETPATH_CFLAGS = @PYTHON_GETPATH_CFLAGS@
 
+PYTHON3_SRC	= @PYTHON3_SRC@
+PYTHON3_OBJ	= @PYTHON3_OBJ@
+PYTHON3_CFLAGS	= @PYTHON3_CFLAGS@
+PYTHON3_LIBS	= @PYTHON3_LIBS@
+PYTHON3_CONFDIR	= @PYTHON3_CONFDIR@
+
 TCL		= @vi_cv_path_tcl@
 TCL_SRC		= @TCL_SRC@
 TCL_OBJ		= @TCL_OBJ@
--- a/src/configure.in
+++ b/src/configure.in
@@ -878,7 +878,7 @@ eof
 	  AC_MSG_RESULT(no)
 	fi
 
-	dnl check that compiling a simple program still works with the flags
+	dnl Check that compiling a simple program still works with the flags
 	dnl added for Python.
 	AC_MSG_CHECKING([if compile and link flags for Python are sane])
 	cflags_save=$CFLAGS
@@ -906,6 +906,7 @@ eof
     fi
   fi
 fi
+
 AC_SUBST(PYTHON_CONFDIR)
 AC_SUBST(PYTHON_LIBS)
 AC_SUBST(PYTHON_GETPATH_CFLAGS)
@@ -913,6 +914,183 @@ AC_SUBST(PYTHON_CFLAGS)
 AC_SUBST(PYTHON_SRC)
 AC_SUBST(PYTHON_OBJ)
 
+
+AC_MSG_CHECKING(--enable-python3interp argument)
+AC_ARG_ENABLE(python3interp,
+	[  --enable-python3interp   Include Python3 interpreter.], ,
+	[enable_python3interp="no"])
+AC_MSG_RESULT($enable_python3interp)
+if test "$enable_python3interp" = "yes"; then
+  dnl -- find the python3 executable
+  AC_PATH_PROG(vi_cv_path_python3, python3)
+  if test "X$vi_cv_path_python3" != "X"; then
+
+    dnl -- get its version number
+    AC_CACHE_CHECK(Python version,vi_cv_var_python3_version,
+    [[vi_cv_var_python3_version=`
+          ${vi_cv_path_python3} -c 'import sys; print(sys.version[1:3])'`
+    ]])
+
+    dnl -- find where python3 thinks it was installed
+    AC_CACHE_CHECK(Python's install prefix,vi_cv_path_python3_pfx,
+    [ vi_cv_path_python3_pfx=`
+     ${vi_cv_path_python3} -c \
+     "import sys; print(sys.prefix)"` ])
+
+    dnl -- and where it thinks it runs
+    AC_CACHE_CHECK(Python's execution prefix,vi_cv_path_python3_epfx,
+    [ vi_cv_path_python3_epfx=`
+     ${vi_cv_path_python3} -c \
+     "import sys; print(sys.exec_prefix)"` ])
+
+    dnl -- python3's internal library path
+
+    AC_CACHE_VAL(vi_cv_path_python3path,
+    [ vi_cv_path_python3path=`
+     unset PYTHONPATH;
+     ${vi_cv_path_python3} -c \
+     "import sys, string; print(':'.join(sys.path))"` ])
+
+    dnl -- where the Python implementation library archives are
+
+    AC_ARG_WITH(python3-config-dir,
+     [  --with-python3-config-dir=PATH  Python's config directory],
+     [ vi_cv_path_python3_conf="${withval}" ] )
+
+    AC_CACHE_CHECK(Python's configuration directory,vi_cv_path_python3_conf,
+    [
+     vi_cv_path_python3_conf=
+     for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do
+       for subdir in lib share; do
+         d="${path}/${subdir}/python3${vi_cv_var_python3_version}/config"
+         if test -d "$d" && test -f "$d/config.c"; then
+           vi_cv_path_python3_conf="$d"
+         fi
+       done
+     done
+    ])
+
+    PYTHON3_CONFDIR="${vi_cv_path_python3_conf}"
+
+    if test "X$PYTHON3_CONFDIR" = "X"; then
+      AC_MSG_RESULT([can't find it!])
+    else
+
+      dnl -- we need to examine Python's config/Makefile too
+      dnl    see what the interpreter is built from
+      AC_CACHE_VAL(vi_cv_path_python3_plibs,
+      [
+          pwd=`pwd`
+          tmp_mkf="$pwd/config-PyMake$$"
+          cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+	@echo "python3_MODLIBS='$(MODLIBS)'"
+	@echo "python3_LIBS='$(LIBS)'"
+	@echo "python3_SYSLIBS='$(SYSLIBS)'"
+	@echo "python3_LINKFORSHARED='$(LINKFORSHARED)'"
+eof
+          dnl -- delete the lines from make about Entering/Leaving directory
+          eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+          rm -f -- "${tmp_mkf}"
+          vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython3${vi_cv_var_python3_version}"
+          vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_MODLIBS} ${python3_LIBS} ${python3_SYSLIBS} ${python3_LINKFORSHARED}"
+          dnl remove -ltermcap, it can conflict with an earlier -lncurses
+          vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//`
+          vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//`
+      ])
+
+      PYTHON3_LIBS="${vi_cv_path_python3_plibs}"
+      if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then
+        PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python3${vi_cv_var_python3_version}"
+      else
+        PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python3${vi_cv_var_python3_version} -I${vi_cv_path_python3_epfx}/include/python3${vi_cv_var_python3_version}"
+      fi
+      PYTHON3_SRC="if_python3.c"
+      dnl For Mac OSX 10.2 config.o is included in the Python library.
+      if test "x$MACOSX" = "xyes"; then
+        PYTHON3_OBJ="objects/if_python3.o"
+      else
+        PYTHON3_OBJ="objects/if_python3.o objects/py3_config.o"
+      fi
+
+      dnl On FreeBSD linking with "-pthread" is required to use threads.
+      dnl _THREAD_SAFE must be used for compiling then.
+      dnl The "-pthread" is added to $LIBS, so that the following check for
+      dnl sigaltstack() will look in libc_r (it's there in libc!).
+      dnl Otherwise, when using GCC, try adding -pthread to $CFLAGS.  GCC
+      dnl will then define target-specific defines, e.g., -D_REENTRANT.
+      dnl Don't do this for Mac OSX, -pthread will generate a warning.
+      AC_MSG_CHECKING([if -pthread should be used])
+      threadsafe_flag=
+      thread_lib=
+      dnl if test "x$MACOSX" != "xyes"; then
+      if test "`(uname) 2>/dev/null`" != Darwin; then
+        test "$GCC" = yes && threadsafe_flag="-pthread"
+        if test "`(uname) 2>/dev/null`" = FreeBSD; then
+          threadsafe_flag="-D_THREAD_SAFE"
+          thread_lib="-pthread"
+        fi
+      fi
+      libs_save_old=$LIBS
+      if test -n "$threadsafe_flag"; then
+        cflags_save=$CFLAGS
+        CFLAGS="$CFLAGS $threadsafe_flag"
+        LIBS="$LIBS $thread_lib"
+        AC_TRY_LINK(,[ ],
+           AC_MSG_RESULT(yes); PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag",
+           AC_MSG_RESULT(no); LIBS=$libs_save_old
+           )
+        CFLAGS=$cflags_save
+      else
+        AC_MSG_RESULT(no)
+      fi
+
+      dnl check that compiling a simple program still works with the flags
+      dnl added for Python.
+      AC_MSG_CHECKING([if compile and link flags for Python are sane])
+      cflags_save=$CFLAGS
+      libs_save=$LIBS
+      CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+      LIBS="$LIBS $PYTHON3_LIBS"
+      AC_TRY_LINK(,[ ],
+             AC_MSG_RESULT(yes); python3_ok=yes,
+             AC_MSG_RESULT(no: PYTHON3 DISABLED); python3_ok=no)
+      CFLAGS=$cflags_save
+      LIBS=$libs_save
+      if test "$python3_ok" = yes; then
+        AC_DEFINE(FEAT_PYTHON3)
+      else
+        LIBS=$libs_save_old
+        PYTHON3_SRC=
+        PYTHON3_OBJ=
+        PYTHON3_LIBS=
+        PYTHON3_CFLAGS=
+      fi
+    fi
+  fi
+fi
+
+AC_SUBST(PYTHON3_CONFDIR)
+AC_SUBST(PYTHON3_LIBS)
+AC_SUBST(PYTHON3_CFLAGS)
+AC_SUBST(PYTHON3_SRC)
+AC_SUBST(PYTHON3_OBJ)
+
+dnl if python2.x and python3.x are enabled one can only link in code
+dnl with dlopen(), dlsym(), dlclose() 
+if test "$python_ok" = yes && test "$python3_ok" = yes; then
+  AC_DEFINE(DYNAMIC_PYTHON)
+  AC_DEFINE(DYNAMIC_PYTHON3)
+  PYTHON_SRC="if_python.c"
+  PYTHON_OBJ="objects/if_python.o"
+  PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"libpython${vi_cv_var_python_version}.so\\\""
+  PYTHON_LIBS=
+  PYTHON3_SRC="if_python3.c"
+  PYTHON3_OBJ="objects/if_python3.o"
+  PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"libpython3${vi_cv_var_python3_version}.so\\\""
+  PYTHON3_LIBS=
+fi
+
 AC_MSG_CHECKING(--enable-tclinterp argument)
 AC_ARG_ENABLE(tclinterp,
 	[  --enable-tclinterp      Include Tcl interpreter.], ,
--- a/src/eval.c
+++ b/src/eval.c
@@ -5911,8 +5911,8 @@ list_equal(l1, l2, ic)
     return item1 == NULL && item2 == NULL;
 }
 
-#if defined(FEAT_RUBY) || defined(FEAT_PYTHON) || defined(FEAT_MZSCHEME) \
-	|| defined(FEAT_LUA) || defined(PROTO)
+#if defined(FEAT_RUBY) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
+	|| defined(FEAT_MZSCHEME) || defined(FEAT_LUA) || defined(PROTO)
 /*
  * Return the dictitem that an entry in a hashtable points to.
  */
@@ -11991,6 +11991,11 @@ f_has(argvars, rettv)
 	"python",
 #endif
 #endif
+#ifdef FEAT_PYTHON3
+#ifndef DYNAMIC_PYTHON3
+	"python3",
+#endif
+#endif
 #ifdef FEAT_POSTSCRIPT
 	"postscript",
 #endif
@@ -12184,10 +12189,18 @@ f_has(argvars, rettv)
 	else if (STRICMP(name, "ruby") == 0)
 	    n = ruby_enabled(FALSE);
 #endif
+#ifdef FEAT_PYTHON
 #ifdef DYNAMIC_PYTHON
 	else if (STRICMP(name, "python") == 0)
 	    n = python_enabled(FALSE);
 #endif
+#endif
+#ifdef FEAT_PYTHON3
+#ifdef DYNAMIC_PYTHON3
+	else if (STRICMP(name, "python3") == 0)
+	    n = python3_enabled(FALSE);
+#endif
+#endif
 #ifdef DYNAMIC_PERL
 	else if (STRICMP(name, "perl") == 0)
 	    n = perl_enabled(FALSE);
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -741,6 +741,10 @@ EX(CMD_python,		"python",	ex_python,
 			RANGE|EXTRA|NEEDARG|CMDWIN),
 EX(CMD_pyfile,		"pyfile",	ex_pyfile,
 			RANGE|FILE1|NEEDARG|CMDWIN),
+EX(CMD_python3,		"py3",	ex_python3,
+			RANGE|EXTRA|NEEDARG|CMDWIN),
+EX(CMD_py3file,		"py3file",	ex_py3file,
+			RANGE|FILE1|NEEDARG|CMDWIN),
 EX(CMD_quit,		"quit",		ex_quit,
 			BANG|TRLBAR|CMDWIN),
 EX(CMD_quitall,		"quitall",	ex_quit_all,
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -129,8 +129,8 @@ static int	getargopt __ARGS((exarg_T *ea
 static int	check_more __ARGS((int, int));
 static linenr_T get_address __ARGS((char_u **, int skip, int to_other_file));
 static void	get_flags __ARGS((exarg_T *eap));
-#if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_TCL) \
-	|| !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME)
+#if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \
+	|| !defined(FEAT_TCL) || !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME)
 # define HAVE_EX_SCRIPT_NI
 static void	ex_script_ni __ARGS((exarg_T *eap));
 #endif
@@ -265,6 +265,10 @@ static void	ex_popup __ARGS((exarg_T *ea
 # define ex_python		ex_script_ni
 # define ex_pyfile		ex_ni
 #endif
+#ifndef FEAT_PYTHON3
+# define ex_python3		ex_script_ni
+# define ex_py3file		ex_ni
+#endif
 #ifndef FEAT_TCL
 # define ex_tcl			ex_script_ni
 # define ex_tcldo		ex_ni
@@ -2554,6 +2558,7 @@ do_one_cmd(cmdlinep, sourcing,
 	    case CMD_perl:
 	    case CMD_psearch:
 	    case CMD_python:
+	    case CMD_python3:
 	    case CMD_return:
 	    case CMD_rightbelow:
 	    case CMD_ruby:
@@ -2816,6 +2821,10 @@ find_command(eap, full)
     {
 	while (ASCII_ISALPHA(*p))
 	    ++p;
+        /* for python 3.x support (:py3, :python3) */
+        if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y')
+	    p = skipdigits(p);
+
 	/* check for non-alpha command */
 	if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
 	    ++p;
--- a/src/globals.h
+++ b/src/globals.h
@@ -1415,9 +1415,13 @@ EXTERN char_u e_isadir2[]	INIT(= N_("E17
 #ifdef FEAT_LIBCALL
 EXTERN char_u e_libcall[]	INIT(= N_("E364: Library call failed for \"%s()\""));
 #endif
-#if defined(DYNAMIC_PERL) || defined(DYNAMIC_PYTHON) || defined(DYNAMIC_RUBY) \
-	|| defined(DYNAMIC_TCL) || defined(DYNAMIC_ICONV) \
-	|| defined(DYNAMIC_GETTEXT) || defined(DYNAMIC_MZSCHEME) \
+#if defined(DYNAMIC_PERL) \
+	|| defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) \
+	|| defined(DYNAMIC_RUBY) \
+	|| defined(DYNAMIC_TCL) \
+	|| defined(DYNAMIC_ICONV) \
+	|| defined(DYNAMIC_GETTEXT) \
+	|| defined(DYNAMIC_MZSCHEME) \
         || defined(DYNAMIC_LUA)
 EXTERN char_u e_loadlib[]	INIT(= N_("E370: Could not load library %s"));
 EXTERN char_u e_loadfunc[]	INIT(= N_("E448: Could not load library function %s"));
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -96,6 +96,19 @@ struct PyMethodDef { Py_ssize_t a; };
 #  define HINSTANCE long_u		/* for generating prototypes */
 # endif
 
+#ifndef _WIN32
+# include <dlfcn.h>
+# define FARPROC void*
+# define HINSTANCE void*
+# define load_dll(n) dlopen((n),RTLD_LAZY)
+# define close_dll dlclose
+# define symbol_from_dll dlsym
+#else
+# define load_dll LoadLibrary
+# define close_dll FreeLibrary
+# define symbol_from_dll GetProcAddress
+#endif
+
 /* This makes if_python.c compile without warnings against Python 2.5
  * on Win32 and Win64. */
 #undef PyRun_SimpleString
@@ -315,7 +328,7 @@ end_dynamic_python(void)
 {
     if (hinstPython)
     {
-	FreeLibrary(hinstPython);
+	close_dll(hinstPython);
 	hinstPython = 0;
     }
 }
@@ -332,7 +345,7 @@ python_runtime_link_init(char *libname, 
 
     if (hinstPython)
 	return OK;
-    hinstPython = LoadLibrary(libname);
+    hinstPython = load_dll(libname);
     if (!hinstPython)
     {
 	if (verbose)
@@ -342,10 +355,10 @@ python_runtime_link_init(char *libname, 
 
     for (i = 0; python_funcname_table[i].ptr; ++i)
     {
-	if ((*python_funcname_table[i].ptr = GetProcAddress(hinstPython,
+	if ((*python_funcname_table[i].ptr = symbol_from_dll(hinstPython,
 			python_funcname_table[i].name)) == NULL)
 	{
-	    FreeLibrary(hinstPython);
+	    close_dll(hinstPython);
 	    hinstPython = 0;
 	    if (verbose)
 		EMSG2(_(e_loadfunc), python_funcname_table[i].name);
new file mode 100644
--- /dev/null
+++ b/src/if_python3.c
@@ -0,0 +1,2796 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved    by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+/*
+ * Python extensions by Paul Moore.
+ * Changes for Unix by David Leonard.
+ *
+ * This consists of four parts:
+ * 1. Python interpreter main program
+ * 2. Python output stream: writes output via [e]msg().
+ * 3. Implementation of the Vim module for Python
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+/*
+ * Roland Puntaier 2009/sept/16:
+ * Adaptations to support both python3.x and python2.x
+ */
+
+// uncomment this if used with the debug version of python
+// #define Py_DEBUG
+
+#include "vim.h"
+
+#include <limits.h>
+
+/* Python.h defines _POSIX_THREADS itself (if needed) */
+#ifdef _POSIX_THREADS
+# undef _POSIX_THREADS
+#endif
+
+#if defined(_WIN32) && defined (HAVE_FCNTL_H)
+# undef HAVE_FCNTL_H
+#endif
+
+#ifdef _DEBUG
+# undef _DEBUG
+#endif
+
+#ifdef HAVE_STDARG_H
+# undef HAVE_STDARG_H   /* Python's config.h defines it as well. */
+#endif
+
+#define PY_SSIZE_T_CLEAN
+
+#ifdef F_BLANK
+# undef F_BLANK
+#endif
+
+#ifdef _POSIX_C_SOURCE  /* defined in feature.h */
+# undef _POSIX_C_SOURCE
+#endif
+
+#include <Python.h>
+#if defined(MACOS) && !defined(MACOS_X_UNIX)
+# include "macglue.h"
+# include <CodeFragments.h>
+#endif
+#undef main /* Defined in python.h - aargh */
+#undef HAVE_FCNTL_H /* Clash with os_win32.h */
+
+static void init_structs(void);
+
+#if defined(DYNAMIC_PYTHON3)
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#define FARPROC void*
+#define HINSTANCE void*
+#define load_dll(n) dlopen((n),RTLD_LAZY)
+#define close_dll dlclose
+#define symbol_from_dll dlsym
+#else
+#define load_dll LoadLibrary
+#define close_dll FreeLibrary
+#define symbol_from_dll GetProcAddress
+#endif
+/*
+ * Wrapper defines
+ */
+#undef PyArg_Parse
+# define PyArg_Parse py3_PyArg_Parse
+#undef PyArg_ParseTuple
+# define PyArg_ParseTuple py3_PyArg_ParseTuple
+# define PyDict_SetItemString py3_PyDict_SetItemString
+# define PyErr_BadArgument py3_PyErr_BadArgument
+# define PyErr_Clear py3_PyErr_Clear
+# define PyErr_NoMemory py3_PyErr_NoMemory
+# define PyErr_Occurred py3_PyErr_Occurred
+# define PyErr_SetNone py3_PyErr_SetNone
+# define PyErr_SetString py3_PyErr_SetString
+# define PyEval_InitThreads py3_PyEval_InitThreads
+# define PyEval_RestoreThread py3_PyEval_RestoreThread
+# define PyEval_SaveThread py3_PyEval_SaveThread
+# define PyGILState_Ensure py3_PyGILState_Ensure
+# define PyGILState_Release py3_PyGILState_Release
+# define PyLong_AsLong py3_PyLong_AsLong
+# define PyLong_FromLong py3_PyLong_FromLong
+# define PyList_GetItem py3_PyList_GetItem
+# define PyList_Append py3_PyList_Append
+# define PyList_New py3_PyList_New
+# define PyList_SetItem py3_PyList_SetItem
+# define PyList_Size py3_PyList_Size
+# define PySlice_GetIndicesEx py3_PySlice_GetIndicesEx
+# define PyImport_ImportModule py3_PyImport_ImportModule
+# define PyObject_Init py3__PyObject_Init
+# define PyDict_New py3_PyDict_New
+# define PyDict_GetItemString py3_PyDict_GetItemString
+# define PyModule_GetDict py3_PyModule_GetDict
+#undef PyRun_SimpleString
+# define PyRun_SimpleString py3_PyRun_SimpleString
+# define PySys_SetObject py3_PySys_SetObject
+# define PySys_SetArgv py3_PySys_SetArgv
+# define PyType_Type (*py3_PyType_Type)
+# define PyType_Ready py3_PyType_Ready
+#undef Py_BuildValue
+# define Py_BuildValue py3_Py_BuildValue
+# define Py_Initialize py3_Py_Initialize
+# define Py_Finalize py3_Py_Finalize
+# define Py_IsInitialized py3_Py_IsInitialized
+# define _Py_NoneStruct (*py3__Py_NoneStruct)
+# define PyModule_AddObject py3_PyModule_AddObject
+# define PyImport_AppendInittab py3_PyImport_AppendInittab
+# define _PyUnicode_AsString py3__PyUnicode_AsString
+# define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
+# define PySlice_Type (*py3_PySlice_Type)
+#ifdef Py_DEBUG
+    # define _Py_NegativeRefcount py3__Py_NegativeRefcount
+    # define _Py_RefTotal (*py3__Py_RefTotal)
+    # define _Py_Dealloc py3__Py_Dealloc
+    # define _PyObject_DebugMalloc py3__PyObject_DebugMalloc
+    # define _PyObject_DebugFree py3__PyObject_DebugFree
+#else
+    # define PyObject_Malloc py3_PyObject_Malloc
+    # define PyObject_Free py3_PyObject_Free
+#endif
+# define PyType_GenericAlloc py3_PyType_GenericAlloc
+# define PyType_GenericNew py3_PyType_GenericNew
+# define PyModule_Create2 py3_PyModule_Create2
+#undef PyUnicode_FromString
+# define PyUnicode_FromString py3_PyUnicode_FromString
+#undef PyUnicode_FromStringAndSize
+# define PyUnicode_FromStringAndSize py3_PyUnicode_FromStringAndSize
+
+#ifdef Py_DEBUG
+#undef PyObject_NEW
+#define PyObject_NEW(type, typeobj) \
+( (type *) PyObject_Init( \
+        (PyObject *) _PyObject_DebugMalloc( _PyObject_SIZE(typeobj) ), (typeobj)) )
+#endif
+/*
+ * Pointers for dynamic link
+ */
+static int (*py3_PySys_SetArgv)(int, wchar_t **);
+static void (*py3_Py_Initialize)(void);
+static PyObject* (*py3_PyList_New)(Py_ssize_t size);
+static PyGILState_STATE (*py3_PyGILState_Ensure)(void);
+static void (*py3_PyGILState_Release)(PyGILState_STATE);
+static int (*py3_PySys_SetObject)(char *, PyObject *);
+static PyObject* (*py3_PyList_Append)(PyObject *, PyObject *);
+static Py_ssize_t (*py3_PyList_Size)(PyObject *);
+static int (*py3_PySlice_GetIndicesEx)(PySliceObject *r, Py_ssize_t length,
+                     Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength);
+static PyObject* (*py3_PyErr_NoMemory)(void);
+static void (*py3_Py_Finalize)(void);
+static void (*py3_PyErr_SetString)(PyObject *, const char *);
+static int (*py3_PyRun_SimpleString)(char *);
+static PyObject* (*py3_PyList_GetItem)(PyObject *, Py_ssize_t);
+static PyObject* (*py3_PyImport_ImportModule)(const char *);
+static int (*py3_PyErr_BadArgument)(void);
+static PyTypeObject* py3_PyType_Type;
+static PyObject* (*py3_PyErr_Occurred)(void);
+static PyObject* (*py3_PyModule_GetDict)(PyObject *);
+static int (*py3_PyList_SetItem)(PyObject *, Py_ssize_t, PyObject *);
+static PyObject* (*py3_PyDict_GetItemString)(PyObject *, const char *);
+static PyObject* (*py3_PyLong_FromLong)(long);
+static PyObject* (*py3_PyDict_New)(void);
+static PyObject* (*py3_Py_BuildValue)(char *, ...);
+static int (*py3_PyType_Ready)(PyTypeObject *type);
+static int (*py3_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
+static PyObject* (*py3_PyUnicode_FromString)(const char *u);
+static PyObject* (*py3_PyUnicode_FromStringAndSize)(const char *u, Py_ssize_t size);
+static long (*py3_PyLong_AsLong)(PyObject *);
+static void (*py3_PyErr_SetNone)(PyObject *);
+static void (*py3_PyEval_InitThreads)(void);
+static void(*py3_PyEval_RestoreThread)(PyThreadState *);
+static PyThreadState*(*py3_PyEval_SaveThread)(void);
+static int (*py3_PyArg_Parse)(PyObject *, char *, ...);
+static int (*py3_PyArg_ParseTuple)(PyObject *, char *, ...);
+static int (*py3_Py_IsInitialized)(void);
+static void (*py3_PyErr_Clear)(void);
+static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
+static PyObject* py3__Py_NoneStruct;
+static int (*py3_PyModule_AddObject)(PyObject *m, const char *name, PyObject *o);
+static int (*py3_PyImport_AppendInittab)(const char *name, PyObject* (*initfunc)(void));
+static char* (*py3__PyUnicode_AsString)(PyObject *unicode);
+static PyObject* (*py3_PyObject_GenericGetAttr)(PyObject *obj, PyObject *name);
+static PyObject* (*py3_PyModule_Create2)(struct PyModuleDef* module, int module_api_version);
+static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
+static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
+static PyTypeObject* py3_PySlice_Type;
+#ifdef Py_DEBUG
+    static void (*py3__Py_NegativeRefcount)(const char *fname, int lineno, PyObject *op);
+    static Py_ssize_t* py3__Py_RefTotal;
+    static void (*py3__Py_Dealloc)(PyObject *obj);
+    static void (*py3__PyObject_DebugFree)(void*);
+    static void* (*py3__PyObject_DebugMalloc)(size_t);
+#else
+    static void (*py3_PyObject_Free)(void*);
+    static void* (*py3_PyObject_Malloc)(size_t);
+#endif
+
+static HINSTANCE hinstPy3 = 0; /* Instance of python.dll */
+
+/* Imported exception objects */
+static PyObject *p3imp_PyExc_AttributeError;
+static PyObject *p3imp_PyExc_IndexError;
+static PyObject *p3imp_PyExc_KeyboardInterrupt;
+static PyObject *p3imp_PyExc_TypeError;
+static PyObject *p3imp_PyExc_ValueError;
+
+# define PyExc_AttributeError p3imp_PyExc_AttributeError
+# define PyExc_IndexError p3imp_PyExc_IndexError
+# define PyExc_KeyboardInterrupt p3imp_PyExc_KeyboardInterrupt
+# define PyExc_TypeError p3imp_PyExc_TypeError
+# define PyExc_ValueError p3imp_PyExc_ValueError
+
+/*
+ * Table of name to function pointer of python.
+ */
+# define PYTHON_PROC FARPROC
+static struct
+{
+    char *name;
+    PYTHON_PROC *ptr;
+} py3_funcname_table[] =
+{
+    {"PySys_SetArgv", (PYTHON_PROC*)&py3_PySys_SetArgv},
+    {"Py_Initialize", (PYTHON_PROC*)&py3_Py_Initialize},
+    {"PyArg_ParseTuple", (PYTHON_PROC*)&py3_PyArg_ParseTuple},
+    {"PyList_New", (PYTHON_PROC*)&py3_PyList_New},
+    {"PyGILState_Ensure", (PYTHON_PROC*)&py3_PyGILState_Ensure},
+    {"PyGILState_Release", (PYTHON_PROC*)&py3_PyGILState_Release},
+    {"PySys_SetObject", (PYTHON_PROC*)&py3_PySys_SetObject},
+    {"PyList_Append", (PYTHON_PROC*)&py3_PyList_Append},
+    {"PyList_Size", (PYTHON_PROC*)&py3_PyList_Size},
+    {"PySlice_GetIndicesEx", (PYTHON_PROC*)&py3_PySlice_GetIndicesEx},
+    {"PyErr_NoMemory", (PYTHON_PROC*)&py3_PyErr_NoMemory},
+    {"Py_Finalize", (PYTHON_PROC*)&py3_Py_Finalize},
+    {"PyErr_SetString", (PYTHON_PROC*)&py3_PyErr_SetString},
+    {"PyRun_SimpleString", (PYTHON_PROC*)&py3_PyRun_SimpleString},
+    {"PyList_GetItem", (PYTHON_PROC*)&py3_PyList_GetItem},
+    {"PyImport_ImportModule", (PYTHON_PROC*)&py3_PyImport_ImportModule},
+    {"PyErr_BadArgument", (PYTHON_PROC*)&py3_PyErr_BadArgument},
+    {"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
+    {"PyErr_Occurred", (PYTHON_PROC*)&py3_PyErr_Occurred},
+    {"PyModule_GetDict", (PYTHON_PROC*)&py3_PyModule_GetDict},
+    {"PyList_SetItem", (PYTHON_PROC*)&py3_PyList_SetItem},
+    {"PyDict_GetItemString", (PYTHON_PROC*)&py3_PyDict_GetItemString},
+    {"PyLong_FromLong", (PYTHON_PROC*)&py3_PyLong_FromLong},
+    {"PyDict_New", (PYTHON_PROC*)&py3_PyDict_New},
+    {"Py_BuildValue", (PYTHON_PROC*)&py3_Py_BuildValue},
+    {"PyType_Ready", (PYTHON_PROC*)&py3_PyType_Ready},
+    {"PyDict_SetItemString", (PYTHON_PROC*)&py3_PyDict_SetItemString},
+    {"PyLong_AsLong", (PYTHON_PROC*)&py3_PyLong_AsLong},
+    {"PyErr_SetNone", (PYTHON_PROC*)&py3_PyErr_SetNone},
+    {"PyEval_InitThreads", (PYTHON_PROC*)&py3_PyEval_InitThreads},
+    {"PyEval_RestoreThread", (PYTHON_PROC*)&py3_PyEval_RestoreThread},
+    {"PyEval_SaveThread", (PYTHON_PROC*)&py3_PyEval_SaveThread},
+    {"PyArg_Parse", (PYTHON_PROC*)&py3_PyArg_Parse},
+    {"PyArg_ParseTuple", (PYTHON_PROC*)&py3_PyArg_ParseTuple},
+    {"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
+    {"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
+    {"PyErr_Clear", (PYTHON_PROC*)&py3_PyErr_Clear},
+    {"PyObject_Init", (PYTHON_PROC*)&py3__PyObject_Init},
+    {"PyModule_AddObject", (PYTHON_PROC*)&py3_PyModule_AddObject},
+    {"PyImport_AppendInittab", (PYTHON_PROC*)&py3_PyImport_AppendInittab},
+    {"_PyUnicode_AsString", (PYTHON_PROC*)&py3__PyUnicode_AsString},
+    {"PyObject_GenericGetAttr", (PYTHON_PROC*)&py3_PyObject_GenericGetAttr},
+    {"PyModule_Create2", (PYTHON_PROC*)&py3_PyModule_Create2},
+    {"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
+    {"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
+    {"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
+#ifdef Py_DEBUG
+    {"_Py_NegativeRefcount", (PYTHON_PROC*)&py3__Py_NegativeRefcount},
+    {"_Py_RefTotal", (PYTHON_PROC*)&py3__Py_RefTotal},
+    {"_Py_Dealloc", (PYTHON_PROC*)&py3__Py_Dealloc},
+    {"_PyObject_DebugFree", (PYTHON_PROC*)&py3__PyObject_DebugFree},
+    {"_PyObject_DebugMalloc", (PYTHON_PROC*)&py3__PyObject_DebugMalloc},
+#else
+    {"PyObject_Malloc", (PYTHON_PROC*)&py3_PyObject_Malloc},
+    {"PyObject_Free", (PYTHON_PROC*)&py3_PyObject_Free},
+#endif
+    {"", NULL},
+};
+
+/*
+ * Free python.dll
+ */
+static void end_dynamic_python3(void)
+{
+    if (hinstPy3)
+    {
+        close_dll(hinstPy3);
+        hinstPy3 = 0;
+    }
+}
+
+/*
+ * Load library and get all pointers.
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+static int py3_runtime_link_init(char *libname, int verbose)
+{
+    int i;
+
+    if (hinstPy3)
+        return OK;
+    hinstPy3 = load_dll(libname);
+
+    if (!hinstPy3)
+    {
+        if (verbose)
+            EMSG2(_(e_loadlib), libname);
+        return FAIL;
+    }
+
+    for (i = 0; py3_funcname_table[i].ptr; ++i)
+    {
+        if ((*py3_funcname_table[i].ptr = symbol_from_dll(hinstPy3,
+                        py3_funcname_table[i].name)) == NULL)
+        {
+            close_dll(hinstPy3);
+            hinstPy3 = 0;
+            if (verbose)
+                EMSG2(_(e_loadfunc), py3_funcname_table[i].name);
+            return FAIL;
+        }
+    }
+
+    /* load unicode functions separately as only the ucs2 or the ucs4 functions
+     * will be present in the library
+     */
+    void *ucs_from_string, *ucs_from_string_and_size;
+
+    ucs_from_string = symbol_from_dll(hinstPy3, "PyUnicodeUCS2_FromString");
+    ucs_from_string_and_size = symbol_from_dll(hinstPy3,
+            "PyUnicodeUCS2_FromStringAndSize");
+    if (!ucs_from_string || !ucs_from_string_and_size)
+    {
+        ucs_from_string = symbol_from_dll(hinstPy3,
+                "PyUnicodeUCS4_FromString");
+        ucs_from_string_and_size = symbol_from_dll(hinstPy3,
+                "PyUnicodeUCS4_FromStringAndSize");
+    }
+    if (ucs_from_string && ucs_from_string_and_size)
+    {
+        py3_PyUnicode_FromString = ucs_from_string;
+        py3_PyUnicode_FromStringAndSize = ucs_from_string_and_size;
+    }
+    else
+    {
+        close_dll(hinstPy3);
+        hinstPy3 = 0;
+        if (verbose)
+            EMSG2(_(e_loadfunc), "PyUnicode_UCSX_*");
+        return FAIL;
+    }
+
+    return OK;
+}
+
+/*
+ * If python is enabled (there is installed python on Windows system) return
+ * TRUE, else FALSE.
+ */
+int python3_enabled(int verbose)
+{
+    return py3_runtime_link_init(DYNAMIC_PYTHON3_DLL, verbose) == OK;
+}
+
+/* Load the standard Python exceptions - don't import the symbols from the
+ * DLL, as this can cause errors (importing data symbols is not reliable).
+ */
+static void get_py3_exceptions __ARGS((void));
+
+static void get_py3_exceptions()
+{
+    PyObject *exmod = PyImport_ImportModule("builtins");
+    PyObject *exdict = PyModule_GetDict(exmod);
+    p3imp_PyExc_AttributeError = PyDict_GetItemString(exdict, "AttributeError");
+    p3imp_PyExc_IndexError = PyDict_GetItemString(exdict, "IndexError");
+    p3imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt");
+    p3imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError");
+    p3imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError");
+    Py_XINCREF(p3imp_PyExc_AttributeError);
+    Py_XINCREF(p3imp_PyExc_IndexError);
+    Py_XINCREF(p3imp_PyExc_KeyboardInterrupt);
+    Py_XINCREF(p3imp_PyExc_TypeError);
+    Py_XINCREF(p3imp_PyExc_ValueError);
+    Py_XDECREF(exmod);
+}
+#endif /* DYNAMIC_PYTHON3 */
+
+static void call_PyObject_Free(void *p)
+{
+#ifdef Py_DEBUG
+    _PyObject_DebugFree(p);
+#else
+    PyObject_Free(p);
+#endif
+}
+static PyObject* call_PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    return PyType_GenericNew(type,args,kwds);
+}
+static PyObject* call_PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
+{
+    return PyType_GenericAlloc(type,nitems);
+}
+
+/******************************************************
+ * Internal function prototypes.
+ */
+
+static void DoPy3Command(exarg_T *, const char *);
+static Py_ssize_t RangeStart;
+static Py_ssize_t RangeEnd;
+
+static void PythonIO_Flush(void);
+static int PythonIO_Init(void);
+static void PythonIO_Fini(void);
+PyMODINIT_FUNC Py3Init_vim(void);
+
+/* Utility functions for the vim/python interface
+ * ----------------------------------------------
+ */
+static PyObject *GetBufferLine(buf_T *, Py_ssize_t);
+
+static int SetBufferLine(buf_T *, Py_ssize_t, PyObject *, Py_ssize_t*);
+static int InsertBufferLines(buf_T *, Py_ssize_t, PyObject *, Py_ssize_t*);
+static PyObject *GetBufferLineList(buf_T *buf, Py_ssize_t lo, Py_ssize_t hi);
+
+static PyObject *LineToString(const char *);
+static char *StringToLine(PyObject *);
+
+static int VimErrorCheck(void);
+
+#define PyErr_SetVim(str) PyErr_SetString(VimError, str)
+
+/******************************************************
+ * 1. Python interpreter main program.
+ */
+
+static int py3initialised = 0;
+
+
+static PyGILState_STATE pygilstate = PyGILState_UNLOCKED;
+
+/*
+ * obtain a lock on the Vim data structures
+ */
+static void Python_Lock_Vim(void)
+{
+}
+
+/*
+ * release a lock on the Vim data structures
+ */
+static void Python_Release_Vim(void)
+{
+}
+
+void python3_end()
+{
+    static int recurse = 0;
+
+    /* If a crash occurs while doing this, don't try again. */
+    if (recurse != 0)
+        return;
+
+    ++recurse;
+
+#ifdef DYNAMIC_PYTHON3
+    if (hinstPy3)
+#endif
+    if (Py_IsInitialized())
+    {
+	// acquire lock before finalizing
+	pygilstate = PyGILState_Ensure();
+
+        PythonIO_Fini();
+        Py_Finalize();
+    }
+
+#ifdef DYNAMIC_PYTHON3
+    end_dynamic_python3();
+#endif
+
+    --recurse;
+}
+
+static int Python3_Init(void)
+{
+    if (!py3initialised)
+    {
+#ifdef DYNAMIC_PYTHON3
+        if (!python3_enabled(TRUE))
+        {
+            EMSG(_("E263: Sorry, this command is disabled, the Python library could not be loaded."));
+            goto fail;
+        }
+#endif
+
+	init_structs();
+
+        /* initialise threads */
+        PyEval_InitThreads();
+
+#if !defined(MACOS) || defined(MACOS_X_UNIX)
+        Py_Initialize();
+#else
+        PyMac_Initialize();
+#endif
+
+#ifdef DYNAMIC_PYTHON3
+        get_py3_exceptions();
+#endif
+
+        if (PythonIO_Init())
+            goto fail;
+
+        PyImport_AppendInittab("vim", Py3Init_vim);
+
+        /* Remove the element from sys.path that was added because of our
+         * argv[0] value in Py3Init_vim().  Previously we used an empty
+         * string, but dependinding on the OS we then get an empty entry or
+         * the current directory in sys.path. */
+        PyRun_SimpleString("import sys; sys.path = list(filter(lambda x: x != '/must>not&exist', sys.path))");
+
+	// lock is created and acquired in PyEval_InitThreads() and thread
+	// state is created in Py_Initialize()
+	// there _PyGILState_NoteThreadState() also sets gilcounter to 1
+	// (python must have threads enabled!)
+	// so the following does both: unlock GIL and save thread state in TLS
+	// without deleting thread state
+	PyGILState_Release(pygilstate);
+
+        py3initialised = 1;
+    }
+
+    return 0;
+
+fail:
+    /* We call PythonIO_Flush() here to print any Python errors.
+     * This is OK, as it is possible to call this function even
+     * if PythonIO_Init() has not completed successfully (it will
+     * not do anything in this case).
+     */
+    PythonIO_Flush();
+    return -1;
+}
+
+/*
+ * External interface
+ */
+static void DoPy3Command(exarg_T *eap, const char *cmd)
+{
+#if defined(MACOS) && !defined(MACOS_X_UNIX)
+    GrafPtr             oldPort;
+#endif
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+    char                *saved_locale;
+#endif
+
+#if defined(MACOS) && !defined(MACOS_X_UNIX)
+    GetPort(&oldPort);
+    /* Check if the Python library is available */
+    if ((Ptr)PyMac_Initialize == (Ptr)kUnresolvedCFragSymbolAddress)
+        goto theend;
+#endif
+    if (Python3_Init())
+        goto theend;
+
+    RangeStart = eap->line1;
+    RangeEnd = eap->line2;
+    Python_Release_Vim();           /* leave vim */
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+    /* Python only works properly when the LC_NUMERIC locale is "C". */
+    saved_locale = setlocale(LC_NUMERIC, NULL);
+    if (saved_locale == NULL || STRCMP(saved_locale, "C") == 0)
+        saved_locale = NULL;
+    else
+    {
+        /* Need to make a copy, value may change when setting new locale. */
+        saved_locale = (char *)vim_strsave((char_u *)saved_locale);
+        (void)setlocale(LC_NUMERIC, "C");
+    }
+#endif
+
+    pygilstate = PyGILState_Ensure();
+
+    PyRun_SimpleString((char *)(cmd));
+
+    PyGILState_Release(pygilstate);
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+    if (saved_locale != NULL)
+    {
+        (void)setlocale(LC_NUMERIC, saved_locale);
+        vim_free(saved_locale);
+    }
+#endif
+
+    Python_Lock_Vim();              /* enter vim */
+    PythonIO_Flush();
+#if defined(MACOS) && !defined(MACOS_X_UNIX)
+    SetPort(oldPort);
+#endif
+
+theend:
+    return;         /* keeps lint happy */
+}
+
+/*
+ * ":python"
+ */
+void ex_python3(exarg_T *eap)
+{
+    char_u *script;
+
+    script = script_get(eap, eap->arg);
+    if (!eap->skip)
+    {
+        if (script == NULL)
+            DoPy3Command(eap, (char *)eap->arg);
+        else
+            DoPy3Command(eap, (char *)script);
+    }
+    vim_free(script);
+}
+
+#define BUFFER_SIZE 2048
+
+/*
+ * ":pyfile"
+ */
+    void
+ex_py3file(exarg_T *eap)
+{
+    static char buffer[BUFFER_SIZE];
+    const char *file;
+    char *p;
+    int i;
+
+    /* Have to do it like this. PyRun_SimpleFile requires you to pass a
+     * stdio file pointer, but Vim and the Python DLL are compiled with
+     * different options under Windows, meaning that stdio pointers aren't
+     * compatible between the two. Yuk.
+     *
+     * construct: exec(compile(open('a_filename').read(), 'a_filename', 'exec'))
+     *
+     * We need to escape any backslashes or single quotes in the file name, so that
+     * Python won't mangle the file name.
+     */
+
+    strcpy(buffer, "exec(compile(open('");
+    p = buffer + 19; /* size of "exec(compile(open('" */
+
+    for (i=0; i<2; ++i)
+    {
+        file = (char *)eap->arg;
+        while (*file && p < buffer + (BUFFER_SIZE - 3))
+        {
+            if (*file == '\\' || *file == '\'')
+                *p++ = '\\';
+            *p++ = *file++;
+        }
+        /* If we didn't finish the file name, we hit a buffer overflow */
+        if (*file != '\0')
+            return;
+        if (i==0)
+        {
+            strcpy(p,"').read(),'");
+            p += 11;
+        }
+        else
+        {
+            strcpy(p,"','exec'))");
+            p += 10;
+        }
+    }
+
+
+    /* Execute the file */
+    DoPy3Command(eap, buffer);
+}
+
+/******************************************************
+ * 2. Python output stream: writes output via [e]msg().
+ */
+
+/* Implementation functions
+ */
+
+static PyObject *OutputGetattro(PyObject *, PyObject *);
+static int OutputSetattro(PyObject *, PyObject *, PyObject *);
+
+static PyObject *OutputWrite(PyObject *, PyObject *);
+static PyObject *OutputWritelines(PyObject *, PyObject *);
+
+typedef void (*writefn)(char_u *);
+static void writer(writefn fn, char_u *str, Py_ssize_t n);
+
+/* Output object definition
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+    long softspace;
+    long error;
+} OutputObject;
+
+static struct PyMethodDef OutputMethods[] = {
+    /* name,        function,           calling,    documentation */
+    {"write",       OutputWrite,        1,          "" },
+    {"writelines",  OutputWritelines,   1,          "" },
+    { NULL,         NULL,               0,          NULL }
+};
+
+static PyTypeObject OutputType;
+
+/*************/
+
+static PyObject * OutputGetattro(PyObject *self, PyObject *nameobj)
+{
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (strcmp(name, "softspace") == 0)
+        return PyLong_FromLong(((OutputObject *)(self))->softspace);
+
+    return PyObject_GenericGetAttr(self, nameobj);
+}
+
+static int OutputSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (val == NULL) {
+        PyErr_SetString(PyExc_AttributeError, _("can't delete OutputObject attributes"));
+        return -1;
+    }
+
+    if (strcmp(name, "softspace") == 0)
+    {
+        if (!PyLong_Check(val)) {
+            PyErr_SetString(PyExc_TypeError, _("softspace must be an integer"));
+            return -1;
+        }
+
+        ((OutputObject *)(self))->softspace = PyLong_AsLong(val);
+        return 0;
+    }
+
+    PyErr_SetString(PyExc_AttributeError, _("invalid attribute"));
+    return -1;
+}
+
+/*************/
+
+static PyObject * OutputWrite(PyObject *self, PyObject *args)
+{
+    int len;
+    char *str;
+    int error = ((OutputObject *)(self))->error;
+
+    if (!PyArg_ParseTuple(args, "s#", &str, &len))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+    writer((writefn)(error ? emsg : msg), (char_u *)str, len);
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject * OutputWritelines(PyObject *self, PyObject *args)
+{
+    Py_ssize_t n;
+    Py_ssize_t i;
+    PyObject *list;
+    int error = ((OutputObject *)(self))->error;
+
+    if (!PyArg_ParseTuple(args, "O", &list))
+        return NULL;
+    Py_INCREF(list);
+
+    if (!PyList_Check(list)) {
+        PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
+        Py_DECREF(list);
+        return NULL;
+    }
+
+    n = PyList_Size(list);
+
+    for (i = 0; i < n; ++i)
+    {
+        PyObject *line = PyList_GetItem(list, i);
+        char *str;
+        Py_ssize_t len;
+
+        if (!PyArg_Parse(line, "s#", &str, &len)) {
+            PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
+            Py_DECREF(list);
+            return NULL;
+        }
+
+        Py_BEGIN_ALLOW_THREADS
+        Python_Lock_Vim();
+        writer((writefn)(error ? emsg : msg), (char_u *)str, len);
+        Python_Release_Vim();
+        Py_END_ALLOW_THREADS
+    }
+
+    Py_DECREF(list);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/* Output buffer management
+ */
+
+static char_u *buffer = NULL;
+static Py_ssize_t buffer_len = 0;
+static Py_ssize_t buffer_size = 0;
+
+static writefn old_fn = NULL;
+
+static void buffer_ensure(Py_ssize_t n)
+{
+    Py_ssize_t new_size;
+    char_u *new_buffer;
+
+    if (n < buffer_size)
+        return;
+
+    new_size = buffer_size;
+    while (new_size < n)
+        new_size += 80;
+
+    if (new_size != buffer_size)
+    {
+        new_buffer = alloc((unsigned)new_size);
+        if (new_buffer == NULL)
+            return;
+
+        if (buffer)
+        {
+            memcpy(new_buffer, buffer, buffer_len);
+            vim_free(buffer);
+        }
+
+        buffer = new_buffer;
+        buffer_size = new_size;
+    }
+}
+
+static void PythonIO_Flush(void)
+{
+    if (old_fn && buffer_len)
+    {
+        buffer[buffer_len] = 0;
+        old_fn(buffer);
+    }
+
+    buffer_len = 0;
+}
+
+static void writer(writefn fn, char_u *str, Py_ssize_t n)
+{
+    char_u *ptr;
+
+    if (fn != old_fn && old_fn != NULL)
+        PythonIO_Flush();
+
+    old_fn = fn;
+
+    while (n > 0 && (ptr = memchr(str, '\n', n)) != NULL)
+    {
+        Py_ssize_t len = ptr - str;
+
+        buffer_ensure(buffer_len + len + 1);
+
+        memcpy(buffer + buffer_len, str, len);
+        buffer_len += len;
+        buffer[buffer_len] = 0;
+        fn(buffer);
+        str = ptr + 1;
+        n -= len + 1;
+        buffer_len = 0;
+    }
+
+    /* Put the remaining text into the buffer for later printing */
+    buffer_ensure(buffer_len + n + 1);
+    memcpy(buffer + buffer_len, str, n);
+    buffer_len += n;
+}
+
+/***************/
+
+static OutputObject Output =
+{
+    PyObject_HEAD_INIT(&OutputType)
+    0,
+    0
+};
+
+static OutputObject Error =
+{
+    PyObject_HEAD_INIT(&OutputType)
+    0,
+    1
+};
+
+static int PythonIO_Init(void)
+{
+    PyType_Ready(&OutputType);
+
+    PySys_SetObject("stdout", (PyObject *)(void *)&Output);
+    PySys_SetObject("stderr", (PyObject *)(void *)&Error);
+
+    if (PyErr_Occurred())
+    {
+        EMSG(_("E264: Python: Error initialising I/O objects"));
+        return -1;
+    }
+
+    return 0;
+}
+static void PythonIO_Fini(void)
+{
+    PySys_SetObject("stdout", NULL);
+    PySys_SetObject("stderr", NULL);
+}
+
+/******************************************************
+ * 3. Implementation of the Vim module for Python
+ */
+
+/* Vim module - Implementation functions
+ * -------------------------------------
+ */
+
+static PyObject *VimError;
+
+static PyObject *VimCommand(PyObject *, PyObject *);
+static PyObject *VimEval(PyObject *, PyObject *);
+
+/* Window type - Implementation functions
+ * --------------------------------------
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+    win_T       *win;
+}
+WindowObject;
+
+#define INVALID_WINDOW_VALUE ((win_T *)(-1))
+
+#define WindowType_Check(obj) ((obj)->ob_base.ob_type == &WindowType)
+
+static PyObject *WindowNew(win_T *);
+
+static void WindowDestructor(PyObject *);
+static PyObject *WindowGetattro(PyObject *, PyObject *);
+static int WindowSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *WindowRepr(PyObject *);
+
+/* Buffer type - Implementation functions
+ * --------------------------------------
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+    buf_T *buf;
+}
+BufferObject;
+
+#define INVALID_BUFFER_VALUE ((buf_T *)(-1))
+
+#define BufferType_Check(obj) ((obj)->ob_base.ob_type == &BufferType)
+
+static PyObject *BufferNew (buf_T *);
+
+static void BufferDestructor(PyObject *);
+
+static PyObject *BufferGetattro(PyObject *, PyObject*);
+static PyObject *BufferRepr(PyObject *);
+
+static Py_ssize_t BufferLength(PyObject *);
+static PyObject *BufferItem(PyObject *, Py_ssize_t);
+static Py_ssize_t BufferAsItem(PyObject *, Py_ssize_t, PyObject *);
+static PyObject* BufferSubscript(PyObject *self, PyObject* idx);
+
+static PyObject *BufferAppend(PyObject *, PyObject *);
+static PyObject *BufferMark(PyObject *, PyObject *);
+static PyObject *BufferRange(PyObject *, PyObject *);
+
+/* Line range type - Implementation functions
+ * --------------------------------------
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+    BufferObject *buf;
+    Py_ssize_t start;
+    Py_ssize_t end;
+}
+RangeObject;
+
+#define RangeType_Check(obj) ((obj)->ob_base.ob_type == &RangeType)
+
+static PyObject *RangeNew(buf_T *, Py_ssize_t, Py_ssize_t);
+
+static void RangeDestructor(PyObject *);
+static PyObject *RangeGetattro(PyObject *, PyObject *);
+static PyObject *RangeRepr(PyObject *);
+static PyObject* RangeSubscript(PyObject *self, PyObject* idx);
+
+static Py_ssize_t RangeLength(PyObject *);
+static PyObject *RangeItem(PyObject *, Py_ssize_t);
+static Py_ssize_t RangeAsItem(PyObject *, Py_ssize_t, PyObject *);
+
+static PyObject *RangeAppend(PyObject *, PyObject *);
+
+/* Window list type - Implementation functions
+ * -------------------------------------------
+ */
+
+static Py_ssize_t WinListLength(PyObject *);
+static PyObject *WinListItem(PyObject *, Py_ssize_t);
+
+/* Buffer list type - Implementation functions
+ * -------------------------------------------
+ */
+
+static Py_ssize_t BufListLength(PyObject *);
+static PyObject *BufListItem(PyObject *, Py_ssize_t);
+
+/* Current objects type - Implementation functions
+ * -----------------------------------------------
+ */
+
+static PyObject *CurrentGetattro(PyObject *, PyObject *);
+static int CurrentSetattro(PyObject *, PyObject *, PyObject *);
+
+/* Vim module - Definitions
+ */
+
+static struct PyMethodDef VimMethods[] = {
+    /* name,         function,          calling,    documentation */
+    {"command",      VimCommand,        1,          "Execute a Vim ex-mode command" },
+    {"eval",         VimEval,           1,          "Evaluate an expression using Vim evaluator" },
+    { NULL,          NULL,              0,          NULL }
+};
+
+/* Vim module - Implementation
+ */
+/*ARGSUSED*/
+static PyObject * VimCommand(PyObject *self UNUSED, PyObject *args)
+{
+    char *cmd;
+    PyObject *result;
+
+    if (!PyArg_ParseTuple(args, "s", &cmd))
+        return NULL;
+
+    PyErr_Clear();
+
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+
+    do_cmdline_cmd((char_u *)cmd);
+    update_screen(VALID);
+
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    if (VimErrorCheck())
+        result = NULL;
+    else
+        result = Py_None;
+
+    Py_XINCREF(result);
+    return result;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Function to translate a typval_T into a PyObject; this will recursively
+ * translate lists/dictionaries into their Python equivalents.
+ *
+ * The depth parameter is to avoid infinite recursion, set it to 1 when
+ * you call VimToPython.
+ */
+static PyObject * VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
+{
+    PyObject    *result;
+    PyObject    *newObj;
+    char        ptrBuf[NUMBUFLEN];
+
+    /* Avoid infinite recursion */
+    if (depth > 100)
+    {
+        Py_INCREF(Py_None);
+        result = Py_None;
+        return result;
+    }
+
+    /* Check if we run into a recursive loop.  The item must be in lookupDict
+     * then and we can use it again. */
+    if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
+            || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
+    {
+        sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U,
+                our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list
+                                           : (long_u)our_tv->vval.v_dict);
+        result = PyDict_GetItemString(lookupDict, ptrBuf);
+        if (result != NULL)
+        {
+            Py_INCREF(result);
+            return result;
+        }
+    }
+
+    if (our_tv->v_type == VAR_STRING)
+    {
+        result = Py_BuildValue("s", our_tv->vval.v_string);
+    }
+    else if (our_tv->v_type == VAR_NUMBER)
+    {
+        char buf[NUMBUFLEN];
+
+        /* For backwards compatibility numbers are stored as strings. */
+        sprintf(buf, "%ld", (long)our_tv->vval.v_number);
+        result = Py_BuildValue("s", buf);
+    }
+# ifdef FEAT_FLOAT
+    else if (our_tv->v_type == VAR_FLOAT)
+    {
+        char buf[NUMBUFLEN];
+
+        sprintf(buf, "%f", our_tv->vval.v_float);
+        result = Py_BuildValue("s", buf);
+    }
+# endif
+    else if (our_tv->v_type == VAR_LIST)
+    {
+        list_T          *list = our_tv->vval.v_list;
+        listitem_T      *curr;
+
+        result = PyList_New(0);
+
+        if (list != NULL)
+        {
+            PyDict_SetItemString(lookupDict, ptrBuf, result);
+
+            for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
+            {
+                newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict);
+                PyList_Append(result, newObj);
+                Py_DECREF(newObj);
+            }
+        }
+    }
+    else if (our_tv->v_type == VAR_DICT)
+    {
+        result = PyDict_New();
+
+        if (our_tv->vval.v_dict != NULL)
+        {
+            hashtab_T   *ht = &our_tv->vval.v_dict->dv_hashtab;
+            long_u      t = ht->ht_used;
+            hashitem_T  *hi;
+            dictitem_T  *di;
+
+            PyDict_SetItemString(lookupDict, ptrBuf, result);
+
+            for (hi = ht->ht_array; t > 0; ++hi)
+            {
+                if (!HASHITEM_EMPTY(hi))
+                {
+                    --t;
+
+                    di = dict_lookup(hi);
+                    newObj = VimToPython(&di->di_tv, depth + 1, lookupDict);
+                    PyDict_SetItemString(result, (char *)hi->hi_key, newObj);
+                    Py_DECREF(newObj);
+                }
+            }
+        }
+    }
+    else
+    {
+        Py_INCREF(Py_None);
+        result = Py_None;
+    }
+
+    return result;
+}
+#endif
+
+/*ARGSUSED*/
+static PyObject * VimEval(PyObject *self UNUSED, PyObject *args)
+{
+#ifdef FEAT_EVAL
+    char        *expr;
+    typval_T    *our_tv;
+    PyObject    *result;
+    PyObject    *lookup_dict;
+
+    if (!PyArg_ParseTuple(args, "s", &expr))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+    our_tv = eval_expr((char_u *)expr, NULL);
+
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    if (our_tv == NULL)
+    {
+        PyErr_SetVim(_("invalid expression"));
+        return NULL;
+    }
+
+    /* Convert the Vim type into a Python type.  Create a dictionary that's
+     * used to check for recursive loops. */
+    lookup_dict = PyDict_New();
+    result = VimToPython(our_tv, 1, lookup_dict);
+    Py_DECREF(lookup_dict);
+
+
+    Py_BEGIN_ALLOW_THREADS
+    Python_Lock_Vim();
+    free_tv(our_tv);
+    Python_Release_Vim();
+    Py_END_ALLOW_THREADS
+
+    return result;
+#else
+    PyErr_SetVim(_("expressions disabled at compile time"));
+    return NULL;
+#endif
+}
+
+/* Common routines for buffers and line ranges
+ * -------------------------------------------
+ */
+
+static int CheckBuffer(BufferObject *this)
+{
+    if (this->buf == INVALID_BUFFER_VALUE)
+    {
+        PyErr_SetVim(_("attempt to refer to deleted buffer"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static PyObject * RBItem(BufferObject *self, Py_ssize_t n, Py_ssize_t start, Py_ssize_t end)
+{
+    if (CheckBuffer(self))
+        return NULL;
+
+    if (n < 0 || n > end - start)
+    {
+        PyErr_SetString(PyExc_IndexError, _("line number out of range"));
+        return NULL;
+    }
+
+    return GetBufferLine(self->buf, n+start);
+}
+
+static Py_ssize_t RBAsItem(BufferObject *self, Py_ssize_t n, PyObject *val, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *new_end)
+{
+    Py_ssize_t len_change;
+
+    if (CheckBuffer(self))
+        return -1;
+
+    if (n < 0 || n > end - start)
+    {
+        PyErr_SetString(PyExc_IndexError, _("line number out of range"));
+        return -1;
+    }
+
+    if (SetBufferLine(self->buf, n+start, val, &len_change) == FAIL)
+        return -1;
+
+    if (new_end)
+        *new_end = end + len_change;
+
+    return 0;
+}
+
+static PyObject * RBSlice(BufferObject *self, Py_ssize_t lo, Py_ssize_t hi, Py_ssize_t start, Py_ssize_t end)
+{
+    Py_ssize_t size;
+
+    if (CheckBuffer(self))
+        return NULL;
+
+    size = end - start + 1;
+
+    if (lo < 0)
+        lo = 0;
+    else if (lo > size)
+        lo = size;
+    if (hi < 0)
+        hi = 0;
+    if (hi < lo)
+        hi = lo;
+    else if (hi > size)
+        hi = size;
+
+    return GetBufferLineList(self->buf, lo+start, hi+start);
+}
+
+static PyObject * RBAppend(BufferObject *self, PyObject *args, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *new_end)
+{
+    PyObject *lines;
+    Py_ssize_t len_change;
+    Py_ssize_t max;
+    Py_ssize_t n;
+
+    if (CheckBuffer(self))
+        return NULL;
+
+    max = n = end - start + 1;
+
+    if (!PyArg_ParseTuple(args, "O|n" , &lines, &n))
+        return NULL;
+
+    if (n < 0 || n > max)
+    {
+        PyErr_SetString(PyExc_ValueError, _("line number out of range"));
+        return NULL;
+    }
+
+    if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL)
+        return NULL;
+
+    if (new_end)
+        *new_end = end + len_change;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static struct PyMethodDef BufferMethods[] = {
+    /* name,        function,           calling,    documentation */
+    {"append",      BufferAppend,       1,          "Append data to Vim buffer" },
+    {"mark",        BufferMark,         1,          "Return (row,col) representing position of named mark" },
+    {"range",       BufferRange,        1,          "Return a range object which represents the part of the given buffer between line numbers s and e" },
+    { NULL,         NULL,               0,          NULL }
+};
+
+static PySequenceMethods BufferAsSeq = {
+    (lenfunc)           BufferLength,       /* sq_length,    len(x)   */
+    (binaryfunc)        0,                  /* sq_concat,    x+y      */
+    (ssizeargfunc)      0,                  /* sq_repeat,    x*n      */
+    (ssizeargfunc)      BufferItem,         /* sq_item,      x[i]     */
+    0,                                      /* was_sq_slice,     x[i:j]   */
+    (ssizeobjargproc)   BufferAsItem,       /* sq_ass_item,  x[i]=v   */
+    0,                                      /* sq_ass_slice, x[i:j]=v */
+    0,					    /* sq_contains */
+    0,					    /* sq_inplace_concat */
+    0,					    /* sq_inplace_repeat */
+};
+
+PyMappingMethods BufferAsMapping = {
+    /* mp_length        */ (lenfunc)BufferLength,
+    /* mp_subscript     */ (binaryfunc)BufferSubscript,
+    /* mp_ass_subscript */ (objobjargproc)0,
+};
+
+
+/* Buffer object - Definitions
+ */
+
+static PyTypeObject BufferType;
+
+static PyObject * BufferNew(buf_T *buf)
+{
+    /* We need to handle deletion of buffers underneath us.
+     * If we add a "b_python3_ref" field to the buf_T structure,
+     * then we can get at it in buf_freeall() in vim. We then
+     * need to create only ONE Python object per buffer - if
+     * we try to create a second, just INCREF the existing one
+     * and return it. The (single) Python object referring to
+     * the buffer is stored in "b_python3_ref".
+     * Question: what to do on a buf_freeall(). We'll probably
+     * have to either delete the Python object (DECREF it to
+     * zero - a bad idea, as it leaves dangling refs!) or
+     * set the buf_T * value to an invalid value (-1?), which
+     * means we need checks in all access functions... Bah.
+     */
+
+    BufferObject *self;
+
+    if (buf->b_python3_ref != NULL)
+    {
+        self = buf->b_python3_ref;
+        Py_INCREF(self);
+    }
+    else
+    {
+        self = PyObject_NEW(BufferObject, &BufferType);
+        buf->b_python3_ref = self;
+        if (self == NULL)
+            return NULL;
+        self->buf = buf;
+    }
+
+    return (PyObject *)(self);
+}
+
+static void BufferDestructor(PyObject *self)
+{
+    BufferObject *this = (BufferObject *)(self);
+
+    if (this->buf && this->buf != INVALID_BUFFER_VALUE)
+        this->buf->b_python3_ref = NULL;
+}
+
+static PyObject * BufferGetattro(PyObject *self, PyObject*nameobj)
+{
+    BufferObject *this = (BufferObject *)(self);
+
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (CheckBuffer(this))
+        return NULL;
+
+    if (strcmp(name, "name") == 0)
+        return Py_BuildValue("s", this->buf->b_ffname);
+    else if (strcmp(name, "number") == 0)
+        return Py_BuildValue("n", this->buf->b_fnum);
+    else if (strcmp(name,"__members__") == 0)
+        return Py_BuildValue("[ss]", "name", "number");
+    else
+        return PyObject_GenericGetAttr(self, nameobj);
+}
+
+static PyObject * BufferRepr(PyObject *self)
+{
+    static char repr[100];
+    BufferObject *this = (BufferObject *)(self);
+
+    if (this->buf == INVALID_BUFFER_VALUE)
+    {
+        vim_snprintf(repr, 100, _("<buffer object (deleted) at %p>"), (self));
+        return PyUnicode_FromString(repr);
+    }
+    else
+    {
+        char *name = (char *)this->buf->b_fname;
+        Py_ssize_t len;
+
+        if (name == NULL)
+            name = "";
+        len = strlen(name);
+
+        if (len > 35)
+            name = name + (35 - len);
+
+        vim_snprintf(repr, 100, "<buffer %s%s>", len > 35 ? "..." : "", name);
+
+        return PyUnicode_FromString(repr);
+    }
+}
+
+/******************/
+
+static Py_ssize_t BufferLength(PyObject *self)
+{
+    if (CheckBuffer((BufferObject *)(self)))
+        return -1;
+
+    return (Py_ssize_t)(((BufferObject *)(self))->buf->b_ml.ml_line_count);
+}
+
+static PyObject * BufferItem(PyObject *self, Py_ssize_t n)
+{
+    return RBItem((BufferObject *)(self), n, 1,
+                  (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count);
+}
+
+static Py_ssize_t BufferAsItem(PyObject *self, Py_ssize_t n, PyObject *val)
+{
+    return RBAsItem((BufferObject *)(self), n, val, 1,
+                     (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+                     NULL);
+}
+
+static PyObject * BufferSlice(PyObject *self, Py_ssize_t lo, Py_ssize_t hi)
+{
+    return RBSlice((BufferObject *)(self), lo, hi, 1,
+                   (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count);
+}
+
+
+static PyObject* BufferSubscript(PyObject *self, PyObject* idx)
+{
+    if (PyLong_Check(idx)) {
+        long _idx = PyLong_AsLong(idx);
+        return BufferItem(self,_idx);
+    } else if (PySlice_Check(idx)) {
+        Py_ssize_t start, stop, step, slicelen;
+
+        if (PySlice_GetIndicesEx((PySliceObject *)idx,
+                                 (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count+1,
+                                 &start, &stop,
+                                 &step, &slicelen) < 0) {
+                return NULL;
+        }
+        return BufferSlice(self,start,stop+1);
+    } else {
+        PyErr_SetString(PyExc_IndexError, "Index must be int or slice");
+        return NULL;
+    }
+}
+
+static PyObject * BufferAppend(PyObject *self, PyObject *args)
+{
+    return RBAppend((BufferObject *)(self), args, 1,
+                    (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+                    NULL);
+}
+
+static PyObject * BufferMark(PyObject *self, PyObject *args)
+{
+    pos_T       *posp;
+    char        *pmark;//test
+    char        mark;
+    buf_T       *curbuf_save;
+
+    if (CheckBuffer((BufferObject *)(self)))
+        return NULL;
+
+    if (!PyArg_ParseTuple(args, "s", &pmark))//test: "c"->"s"
+        return NULL;
+    mark = *pmark;//test
+
+    curbuf_save = curbuf;
+    curbuf = ((BufferObject *)(self))->buf;
+    posp = getmark(mark, FALSE);
+    curbuf = curbuf_save;
+
+    if (posp == NULL)
+    {
+        PyErr_SetVim(_("invalid mark name"));
+        return NULL;
+    }
+
+    /* Ckeck for keyboard interrupt */
+    if (VimErrorCheck())
+        return NULL;
+
+    if (posp->lnum <= 0)
+    {
+        /* Or raise an error? */
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col));
+}
+
+static PyObject * BufferRange(PyObject *self, PyObject *args)
+{
+    Py_ssize_t start;
+    Py_ssize_t end;
+
+    if (CheckBuffer((BufferObject *)(self)))
+        return NULL;
+
+    if (!PyArg_ParseTuple(args, "nn", &start, &end))
+        return NULL;
+
+    return RangeNew(((BufferObject *)(self))->buf, start, end);
+}
+
+/* Line range object - Definitions
+ */
+
+static struct PyMethodDef RangeMethods[] = {
+    /* name,        function,           calling,    documentation */
+    {"append",      RangeAppend,        1,          "Append data to the Vim range" },
+    { NULL,         NULL,               0,          NULL }
+};
+
+static PySequenceMethods RangeAsSeq = {
+    (lenfunc)           RangeLength,     /* sq_length,    len(x)   */
+    (binaryfunc)        0,               /* RangeConcat, */          /* sq_concat,    x+y      */
+    (ssizeargfunc)      0,               /* RangeRepeat, */        /* sq_repeat,    x*n      */
+    (ssizeargfunc)      RangeItem,       /* sq_item,      x[i]     */
+    0,                                   /* was_sq_slice,     x[i:j]   */
+    (ssizeobjargproc)   RangeAsItem,     /* sq_as_item,  x[i]=v   */
+    0,                                      /* sq_ass_slice, x[i:j]=v */
+    0,					    /* sq_contains */
+    0,					    /* sq_inplace_concat */
+    0,					    /* sq_inplace_repeat */
+};
+
+PyMappingMethods RangeAsMapping = {
+    /* mp_length        */ (lenfunc)RangeLength,
+    /* mp_subscript     */ (binaryfunc)RangeSubscript,
+    /* mp_ass_subscript */ (objobjargproc)0,
+};
+
+static PyTypeObject RangeType;
+
+/* Line range object - Implementation
+ */
+
+static PyObject * RangeNew(buf_T *buf, Py_ssize_t start, Py_ssize_t end)
+{
+    BufferObject *bufr;
+    RangeObject *self;
+    self = PyObject_NEW(RangeObject, &RangeType);
+    if (self == NULL)
+        return NULL;
+
+    bufr = (BufferObject *)BufferNew(buf);
+    if (bufr == NULL)
+    {
+        Py_DECREF(self);
+        return NULL;
+    }
+    Py_INCREF(bufr);
+
+    self->buf = bufr;
+    self->start = start;
+    self->end = end;
+
+    return (PyObject *)(self);
+}
+
+static void RangeDestructor(PyObject *self)
+{
+    Py_DECREF(((RangeObject *)(self))->buf);
+}
+
+static PyObject * RangeGetattro(PyObject *self, PyObject *nameobj)
+{
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (strcmp(name, "start") == 0)
+        return Py_BuildValue("n", ((RangeObject *)(self))->start - 1);
+    else if (strcmp(name, "end") == 0)
+        return Py_BuildValue("n", ((RangeObject *)(self))->end - 1);
+    else
+        return PyObject_GenericGetAttr(self, nameobj);
+}
+
+static PyObject * RangeRepr(PyObject *self)
+{
+    static char repr[100];
+    RangeObject *this = (RangeObject *)(self);
+
+    if (this->buf->buf == INVALID_BUFFER_VALUE)
+    {
+        vim_snprintf(repr, 100, "<range object (for deleted buffer) at %p>",
+                                                                      (self));
+        return PyUnicode_FromString(repr);
+    }
+    else
+    {
+        char *name = (char *)this->buf->buf->b_fname;
+        int len;
+
+        if (name == NULL)
+            name = "";
+        len = (int)strlen(name);
+
+        if (len > 45)
+            name = name + (45 - len);
+
+        vim_snprintf(repr, 100, "<range %s%s (%d:%d)>",
+                len > 45 ? "..." : "", name,
+                this->start, this->end);
+
+        return PyUnicode_FromString(repr);
+    }
+}
+
+/****************/
+
+static Py_ssize_t RangeLength(PyObject *self)
+{
+    /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */
+    if (CheckBuffer(((RangeObject *)(self))->buf))
+        return -1; /* ??? */
+
+    return (((RangeObject *)(self))->end - ((RangeObject *)(self))->start + 1);
+}
+
+static PyObject * RangeItem(PyObject *self, Py_ssize_t n)
+{
+    return RBItem(((RangeObject *)(self))->buf, n,
+                  ((RangeObject *)(self))->start,
+                  ((RangeObject *)(self))->end);
+}
+
+static Py_ssize_t RangeAsItem(PyObject *self, Py_ssize_t n, PyObject *val)
+{
+    return RBAsItem(((RangeObject *)(self))->buf, n, val,
+                     ((RangeObject *)(self))->start,
+                     ((RangeObject *)(self))->end,
+                     &((RangeObject *)(self))->end);
+}
+
+static PyObject * RangeSlice(PyObject *self, Py_ssize_t lo, Py_ssize_t hi)
+{
+    return RBSlice(((RangeObject *)(self))->buf, lo, hi,
+                   ((RangeObject *)(self))->start,
+                   ((RangeObject *)(self))->end);
+}
+
+static PyObject* RangeSubscript(PyObject *self, PyObject* idx)
+{
+    if (PyLong_Check(idx)) {
+        long _idx = PyLong_AsLong(idx);
+        return RangeItem(self,_idx);
+    } else if (PySlice_Check(idx)) {
+        Py_ssize_t start, stop, step, slicelen;
+
+        if (PySlice_GetIndicesEx((PySliceObject *)idx,
+                                 ((RangeObject *)(self))->end-((RangeObject *)(self))->start+1,
+                                 &start, &stop,
+                                 &step, &slicelen) < 0) {
+                return NULL;
+        }
+        return RangeSlice(self,start,stop+1);
+    } else {
+        PyErr_SetString(PyExc_IndexError, "Index must be int or slice");
+        return NULL;
+    }
+}
+
+static PyObject * RangeAppend(PyObject *self, PyObject *args)
+{
+    return RBAppend(((RangeObject *)(self))->buf, args,
+                    ((RangeObject *)(self))->start,
+                    ((RangeObject *)(self))->end,
+                    &((RangeObject *)(self))->end);
+}
+
+/* Buffer list object - Definitions
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+}
+BufListObject;
+
+static PySequenceMethods BufListAsSeq = {
+    (lenfunc)           BufListLength,      /* sq_length,    len(x)   */
+    (binaryfunc)        0,                  /* sq_concat,    x+y      */
+    (ssizeargfunc)      0,                  /* sq_repeat,    x*n      */
+    (ssizeargfunc)      BufListItem,        /* sq_item,      x[i]     */
+    0,                                      /* was_sq_slice,     x[i:j]   */
+    (ssizeobjargproc)   0,                  /* sq_as_item,  x[i]=v   */
+    0,                                      /* sq_ass_slice, x[i:j]=v */
+    0,					    /* sq_contains */
+    0,					    /* sq_inplace_concat */
+    0,					    /* sq_inplace_repeat */
+};
+
+static PyTypeObject BufListType;
+
+/* Buffer list object - Implementation
+ */
+
+/*ARGSUSED*/
+static Py_ssize_t BufListLength(PyObject *self UNUSED)
+{
+    buf_T       *b = firstbuf;
+    Py_ssize_t  n = 0;
+
+    while (b)
+    {
+        ++n;
+        b = b->b_next;
+    }
+
+    return n;
+}
+
+/*ARGSUSED*/
+static PyObject * BufListItem(PyObject *self UNUSED, Py_ssize_t n)
+{
+    buf_T *b;
+
+    for (b = firstbuf; b; b = b->b_next, --n)
+    {
+        if (n == 0)
+            return BufferNew(b);
+    }
+
+    PyErr_SetString(PyExc_IndexError, _("no such buffer"));
+    return NULL;
+}
+
+/* Window object - Definitions
+ */
+
+static struct PyMethodDef WindowMethods[] = {
+    /* name,        function,           calling,    documentation */
+    { NULL,         NULL,               0,          NULL }
+};
+
+static PyTypeObject WindowType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "vim.window",             /* tp_name */
+    sizeof(WindowObject), /* tp_basicsize */
+    0,                         /* tp_itemsize */
+    WindowDestructor,                         /* tp_dealloc */
+    0,                         /* tp_print */
+    0,                         /* tp_getattr */
+    0,                         /* tp_setattr */
+    0,                         /* tp_reserved */
+    WindowRepr,                         /* tp_repr */
+    0,                         /* tp_as_number */
+    0,                         /* tp_as_sequence */
+    0,                         /* tp_as_mapping */
+    0,                         /* tp_hash  */
+    0,                         /* tp_call */
+    0,                         /* tp_str */
+    WindowGetattro,            /* tp_getattro */
+    WindowSetattro,            /* tp_setattro */
+    0,                         /* tp_as_Window */
+    Py_TPFLAGS_DEFAULT,        /* tp_flags */
+    "vim Window object",      /* tp_doc */
+    0,                         /*tp_traverse*/
+    0,                         /*tp_clear*/
+    0,                         /*tp_richcompare*/
+    0,                         /*tp_weaklistoffset*/
+    0,                         /*tp_iter*/
+    0,                         /*tp_iternext*/
+    WindowMethods,             /*tp_methods*/
+    0,                         /*tp_members*/
+    0,                         /*tp_getset*/
+    0,                         /*tp_base*/
+    0,                         /*tp_dict*/
+    0,                         /*tp_descr_get*/
+    0,                         /*tp_descr_set*/
+    0,                         /*tp_dictoffset*/
+    0,                         /*tp_init*/
+    call_PyType_GenericAlloc,       /*tp_alloc*/
+    call_PyType_GenericNew,         /*tp_new*/
+    call_PyObject_Free,             /*tp_free*/
+    0,                         /*tp_is_gc*/
+    0,				/*tp_bases*/
+    0,				/*tp_mro*/
+    0,				/*tp_cache*/
+    0,				/*tp_subclasses*/
+    0,				/*tp_weaklist*/
+    0,				/*tp_del*/
+    0,				/*tp_version_tag*/
+};
+
+/* Window object - Implementation
+ */
+
+static PyObject * WindowNew(win_T *win)
+{
+    /* We need to handle deletion of windows underneath us.
+     * If we add a "w_python3_ref" field to the win_T structure,
+     * then we can get at it in win_free() in vim. We then
+     * need to create only ONE Python object per window - if
+     * we try to create a second, just INCREF the existing one
+     * and return it. The (single) Python object referring to
+     * the window is stored in "w_python3_ref".
+     * On a win_free() we set the Python object's win_T* field
+     * to an invalid value. We trap all uses of a window
+     * object, and reject them if the win_T* field is invalid.
+     */
+
+    WindowObject *self;
+
+    if (win->w_python3_ref)
+    {
+        self = win->w_python3_ref;
+        Py_INCREF(self);
+    }
+    else
+    {
+        self = PyObject_NEW(WindowObject, &WindowType);
+        if (self == NULL)
+            return NULL;
+        self->win = win;
+        win->w_python3_ref = self;
+    }
+
+    return (PyObject *)(self);
+}
+
+static void WindowDestructor(PyObject *self)
+{
+    WindowObject *this = (WindowObject *)(self);
+
+    if (this->win && this->win != INVALID_WINDOW_VALUE)
+        this->win->w_python3_ref = NULL;
+}
+
+static int CheckWindow(WindowObject *this)
+{
+    if (this->win == INVALID_WINDOW_VALUE)
+    {
+        PyErr_SetVim(_("attempt to refer to deleted window"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static PyObject * WindowGetattro(PyObject *self, PyObject *nameobj)
+{
+    WindowObject *this = (WindowObject *)(self);
+
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+
+    if (CheckWindow(this))
+        return NULL;
+
+    if (strcmp(name, "buffer") == 0)
+        return (PyObject *)BufferNew(this->win->w_buffer);
+    else if (strcmp(name, "cursor") == 0)
+    {
+        pos_T *pos = &this->win->w_cursor;
+
+        return Py_BuildValue("(ll)", (long)(pos->lnum), (long)(pos->col));
+    }
+    else if (strcmp(name, "height") == 0)
+        return Py_BuildValue("l", (long)(this->win->w_height));
+#ifdef FEAT_VERTSPLIT
+    else if (strcmp(name, "width") == 0)
+        return Py_BuildValue("l", (long)(W_WIDTH(this->win)));
+#endif
+    else if (strcmp(name,"__members__") == 0)
+        return Py_BuildValue("[sss]", "buffer", "cursor", "height");
+    else
+        return PyObject_GenericGetAttr(self, nameobj);
+}
+
+static int WindowSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+    WindowObject *this = (WindowObject *)(self);
+
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+
+    if (CheckWindow(this))
+        return -1;
+
+    if (strcmp(name, "buffer") == 0)
+    {
+        PyErr_SetString(PyExc_TypeError, _("readonly attribute"));
+        return -1;
+    }
+    else if (strcmp(name, "cursor") == 0)
+    {
+        long lnum;
+        long col;
+
+        if (!PyArg_Parse(val, "(ll)", &lnum, &col))
+            return -1;
+
+        if (lnum <= 0 || lnum > this->win->w_buffer->b_ml.ml_line_count)
+        {
+            PyErr_SetVim(_("cursor position outside buffer"));
+            return -1;
+        }
+
+        /* Check for keyboard interrupts */
+        if (VimErrorCheck())
+            return -1;
+
+        /* NO CHECK ON COLUMN - SEEMS NOT TO MATTER */
+
+        this->win->w_cursor.lnum = lnum;
+        this->win->w_cursor.col = col;
+        update_screen(VALID);
+
+        return 0;
+    }
+    else if (strcmp(name, "height") == 0)
+    {
+        int     height;
+        win_T   *savewin;
+
+        if (!PyArg_Parse(val, "i", &height))
+            return -1;
+
+#ifdef FEAT_GUI
+        need_mouse_correct = TRUE;
+#endif
+        savewin = curwin;
+        curwin = this->win;
+        win_setheight(height);
+        curwin = savewin;
+
+        /* Check for keyboard interrupts */
+        if (VimErrorCheck())
+            return -1;
+
+        return 0;
+    }
+#ifdef FEAT_VERTSPLIT
+    else if (strcmp(name, "width") == 0)
+    {
+        int     width;
+        win_T   *savewin;
+
+        if (!PyArg_Parse(val, "i", &width))
+            return -1;
+
+#ifdef FEAT_GUI
+        need_mouse_correct = TRUE;
+#endif
+        savewin = curwin;
+        curwin = this->win;
+        win_setwidth(width);
+        curwin = savewin;
+
+        /* Check for keyboard interrupts */
+        if (VimErrorCheck())
+            return -1;
+
+        return 0;
+    }
+#endif
+    else
+    {
+        PyErr_SetString(PyExc_AttributeError, name);
+        return -1;
+    }
+}
+
+static PyObject * WindowRepr(PyObject *self)
+{
+    static char repr[100];
+    WindowObject *this = (WindowObject *)(self);
+
+    if (this->win == INVALID_WINDOW_VALUE)
+    {
+        vim_snprintf(repr, 100, _("<window object (deleted) at %p>"), (self));
+        return PyUnicode_FromString(repr);
+    }
+    else
+    {
+        int     i = 0;
+        win_T   *w;
+
+        for (w = firstwin; w != NULL && w != this->win; w = W_NEXT(w))
+            ++i;
+
+        if (w == NULL)
+            vim_snprintf(repr, 100, _("<window object (unknown) at %p>"),
+                                                                      (self));
+        else
+            vim_snprintf(repr, 100, _("<window %d>"), i);
+
+        return PyUnicode_FromString(repr);
+    }
+}
+
+/* Window list object - Definitions
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+}
+WinListObject;
+
+static PySequenceMethods WinListAsSeq = {
+    (lenfunc)        WinListLength,         /* sq_length,    len(x)   */
+    (binaryfunc)     0,                     /* sq_concat,    x+y      */
+    (ssizeargfunc)   0,                     /* sq_repeat,    x*n      */
+    (ssizeargfunc)   WinListItem,           /* sq_item,      x[i]     */
+    0,                                      /* sq_slice,     x[i:j]   */
+    (ssizeobjargproc)0,                     /* sq_as_item,  x[i]=v   */
+    0,                                      /* sq_ass_slice, x[i:j]=v */
+    0,					    /* sq_contains */
+    0,					    /* sq_inplace_concat */
+    0,					    /* sq_inplace_repeat */
+};
+
+static PyTypeObject WinListType;
+
+/* Window list object - Implementation
+ */
+/*ARGSUSED*/
+static Py_ssize_t WinListLength(PyObject *self UNUSED)
+{
+    win_T       *w = firstwin;
+    Py_ssize_t  n = 0;
+
+    while (w != NULL)
+    {
+        ++n;
+        w = W_NEXT(w);
+    }
+
+    return n;
+}
+
+/*ARGSUSED*/
+static PyObject * WinListItem(PyObject *self UNUSED, Py_ssize_t n)
+{
+    win_T *w;
+
+    for (w = firstwin; w != NULL; w = W_NEXT(w), --n)
+        if (n == 0)
+            return WindowNew(w);
+
+    PyErr_SetString(PyExc_IndexError, _("no such window"));
+    return NULL;
+}
+
+/* Current items object - Definitions
+ */
+
+typedef struct
+{
+    PyObject_HEAD
+}
+CurrentObject;
+
+static PyTypeObject CurrentType;
+
+/* Current items object - Implementation
+ */
+/*ARGSUSED*/
+static PyObject * CurrentGetattro(PyObject *self UNUSED, PyObject *nameobj)
+{
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (strcmp(name, "buffer") == 0)
+        return (PyObject *)BufferNew(curbuf);
+    else if (strcmp(name, "window") == 0)
+        return (PyObject *)WindowNew(curwin);
+    else if (strcmp(name, "line") == 0)
+        return GetBufferLine(curbuf, (Py_ssize_t)curwin->w_cursor.lnum);
+    else if (strcmp(name, "range") == 0)
+        return RangeNew(curbuf, RangeStart, RangeEnd);
+    else if (strcmp(name,"__members__") == 0)
+        return Py_BuildValue("[ssss]", "buffer", "window", "line", "range");
+    else
+    {
+        PyErr_SetString(PyExc_AttributeError, name);
+        return NULL;
+    }
+}
+
+/*ARGSUSED*/
+static int CurrentSetattro(PyObject *self UNUSED, PyObject *nameobj, PyObject *value)
+{
+    char *name = "";
+    if (PyUnicode_Check(nameobj))
+        name = _PyUnicode_AsString(nameobj);
+
+    if (strcmp(name, "line") == 0)
+    {
+        if (SetBufferLine(curbuf, (Py_ssize_t)curwin->w_cursor.lnum, value, NULL) == FAIL)
+            return -1;
+
+        return 0;
+    }
+    else
+    {
+        PyErr_SetString(PyExc_AttributeError, name);
+        return -1;
+    }
+}
+
+/* External interface
+ */
+
+    void
+python3_buffer_free(buf_T *buf)
+{
+    if (buf->b_python3_ref != NULL)
+    {
+        BufferObject *bp = buf->b_python3_ref;
+        bp->buf = INVALID_BUFFER_VALUE;
+        buf->b_python3_ref = NULL;
+    }
+}
+
+#if defined(FEAT_WINDOWS) || defined(PROTO)
+    void
+python3_window_free(win_T *win)
+{
+    if (win->w_python3_ref != NULL)
+    {
+        WindowObject *wp = win->w_python3_ref;
+        wp->win = INVALID_WINDOW_VALUE;
+        win->w_python3_ref = NULL;
+    }
+}
+#endif
+
+static BufListObject TheBufferList =
+{
+    PyObject_HEAD_INIT(&BufListType)
+};
+
+static WinListObject TheWindowList =
+{
+    PyObject_HEAD_INIT(&WinListType)
+};
+
+static CurrentObject TheCurrent =
+{
+    PyObject_HEAD_INIT(&CurrentType)
+};
+
+PyDoc_STRVAR(vim_module_doc,"vim python interface\n");
+
+static struct PyModuleDef vimmodule;
+
+PyMODINIT_FUNC Py3Init_vim(void)
+{
+    PyObject *mod;
+    /* The special value is removed from sys.path in Python3_Init(). */
+    static wchar_t *(argv[2]) = {L"/must>not&exist/foo", NULL};
+
+    PyType_Ready(&BufferType);
+    PyType_Ready(&RangeType);
+    PyType_Ready(&WindowType);
+    PyType_Ready(&BufListType);
+    PyType_Ready(&WinListType);
+    PyType_Ready(&CurrentType);
+
+    /* Set sys.argv[] to avoid a crash in warn(). */
+    PySys_SetArgv(1, argv);
+
+    mod = PyModule_Create(&vimmodule);
+
+    VimError = Py_BuildValue("s", "vim.error");
+
+    PyModule_AddObject(mod, "error", VimError);
+    Py_INCREF((PyObject *)(void *)&TheBufferList);
+    PyModule_AddObject(mod, "buffers", (PyObject *)(void *)&TheBufferList);
+    Py_INCREF((PyObject *)(void *)&TheCurrent);
+    PyModule_AddObject(mod, "current", (PyObject *)(void *)&TheCurrent);
+    Py_INCREF((PyObject *)(void *)&TheWindowList);
+    PyModule_AddObject(mod, "windows", (PyObject *)(void *)&TheWindowList);
+
+    if (PyErr_Occurred())
+        return NULL;
+
+    return mod;
+}
+
+/*************************************************************************
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+
+/* Get a list of lines from the specified buffer. The line numbers
+ * are in Vim format (1-based). The range is from lo up to, but not
+ * including, hi. The list is returned as a Python list of string objects.
+ */
+static PyObject * GetBufferLineList(buf_T *buf, Py_ssize_t lo, Py_ssize_t hi)
+{
+    Py_ssize_t i;
+    Py_ssize_t n = hi - lo;
+    PyObject *list = PyList_New(n);
+
+    if (list == NULL)
+        return NULL;
+
+    for (i = 0; i < n; ++i)
+    {
+        PyObject *str = LineToString((char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE));
+
+        /* Error check - was the Python string creation OK? */
+        if (str == NULL)
+        {
+            Py_DECREF(list);
+            return NULL;
+        }
+
+        /* Set the list item */
+        if (PyList_SetItem(list, i, str))
+        {
+            Py_DECREF(str);
+            Py_DECREF(list);
+            return NULL;
+        }
+    }
+
+    /* The ownership of the Python list is passed to the caller (ie,
+     * the caller should Py_DECREF() the object when it is finished
+     * with it).
+     */
+
+    return list;
+}
+
+/* Get a line from the specified buffer. The line number is
+ * in Vim format (1-based). The line is returned as a Python
+ * string object.
+ */
+static PyObject * GetBufferLine(buf_T *buf, Py_ssize_t n)
+{
+    return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE));
+}
+
+/*
+ * Check if deleting lines made the cursor position invalid.
+ * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
+ * deleted).
+ */
+static void py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
+{
+    if (curwin->w_cursor.lnum >= lo)
+    {
+        /* Adjust the cursor position if it's in/after the changed
+         * lines. */
+        if (curwin->w_cursor.lnum >= hi)
+        {
+            curwin->w_cursor.lnum += extra;
+            check_cursor_col();
+        }
+        else if (extra < 0)
+        {
+            curwin->w_cursor.lnum = lo;
+            check_cursor();
+        }
+        else
+            check_cursor_col();
+        changed_cline_bef_curs();
+    }
+    invalidate_botline();
+}
+
+/* Replace a line in the specified buffer. The line number is
+ * in Vim format (1-based). The replacement line is given as
+ * a Python string object. The object is checked for validity
+ * and correct format. Errors are returned as a value of FAIL.
+ * The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+static int SetBufferLine(buf_T *buf, Py_ssize_t n, PyObject *line, Py_ssize_t *len_change)
+{
+    /* First of all, we check the thpe of the supplied Python object.
+     * There are three cases:
+     *    1. NULL, or None - this is a deletion.
+     *    2. A string      - this is a replacement.
+     *    3. Anything else - this is an error.
+     */
+    if (line == Py_None || line == NULL)
+    {
+        buf_T *savebuf = curbuf;
+
+        PyErr_Clear();
+        curbuf = buf;
+
+        if (u_savedel((linenr_T)n, 1L) == FAIL)
+            PyErr_SetVim(_("cannot save undo information"));
+        else if (ml_delete((linenr_T)n, FALSE) == FAIL)
+            PyErr_SetVim(_("cannot delete line"));
+        else
+        {
+            deleted_lines_mark((linenr_T)n, 1L);
+            if (buf == curwin->w_buffer)
+                py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1);
+        }
+
+        curbuf = savebuf;
+
+        if (PyErr_Occurred() || VimErrorCheck())
+            return FAIL;
+
+        if (len_change)
+            *len_change = -1;
+
+        return OK;
+    }
+    else if (PyUnicode_Check(line))
+    {
+        char *save = StringToLine(line);
+        buf_T *savebuf = curbuf;
+
+        if (save == NULL)
+            return FAIL;
+
+        /* We do not need to free "save" if ml_replace() consumes it. */
+        PyErr_Clear();
+        curbuf = buf;
+
+        if (u_savesub((linenr_T)n) == FAIL)
+        {
+            PyErr_SetVim(_("cannot save undo information"));
+            vim_free(save);
+        }
+        else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL)
+        {
+            PyErr_SetVim(_("cannot replace line"));
+            vim_free(save);
+        }
+        else
+            changed_bytes((linenr_T)n, 0);
+
+        curbuf = savebuf;
+
+        /* Check that the cursor is not beyond the end of the line now. */
+        if (buf == curwin->w_buffer)
+            check_cursor_col();
+
+        if (PyErr_Occurred() || VimErrorCheck())
+            return FAIL;
+
+        if (len_change)
+            *len_change = 0;
+
+        return OK;
+    }
+    else
+    {
+        PyErr_BadArgument();
+        return FAIL;
+    }
+}
+
+/* Insert a number of lines into the specified buffer after the specifed line.
+ * The line number is in Vim format (1-based). The lines to be inserted are
+ * given as a Python list of string objects or as a single string. The lines
+ * to be added are checked for validity and correct format. Errors are
+ * returned as a value of FAIL.  The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+static int InsertBufferLines(buf_T *buf, Py_ssize_t n, PyObject *lines, Py_ssize_t *len_change)
+{
+    /* First of all, we check the type of the supplied Python object.
+     * It must be a string or a list, or the call is in error.
+     */
+    if (PyUnicode_Check(lines))
+    {
+        char    *str = StringToLine(lines);
+        buf_T   *savebuf;
+
+        if (str == NULL)
+            return FAIL;
+
+        savebuf = curbuf;
+
+        PyErr_Clear();
+        curbuf = buf;
+
+        if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
+            PyErr_SetVim(_("cannot save undo information"));
+        else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
+            PyErr_SetVim(_("cannot insert line"));
+        else
+            appended_lines_mark((linenr_T)n, 1L);
+
+        vim_free(str);
+        curbuf = savebuf;
+        update_screen(VALID);
+
+        if (PyErr_Occurred() || VimErrorCheck())
+            return FAIL;
+
+        if (len_change)
+            *len_change = 1;
+
+        return OK;
+    }
+    else if (PyList_Check(lines))
+    {
+        Py_ssize_t      i;
+        Py_ssize_t      size = PyList_Size(lines);
+        char    **array;
+        buf_T   *savebuf;
+
+        array = (char **)alloc((unsigned)(size * sizeof(char *)));
+        if (array == NULL)
+        {
+            PyErr_NoMemory();
+            return FAIL;
+        }
+
+        for (i = 0; i < size; ++i)
+        {
+            PyObject *line = PyList_GetItem(lines, i);
+            array[i] = StringToLine(line);
+
+            if (array[i] == NULL)
+            {
+                while (i)
+                    vim_free(array[--i]);
+                vim_free(array);
+                return FAIL;
+            }
+        }
+
+        savebuf = curbuf;
+
+        PyErr_Clear();
+        curbuf = buf;
+
+        if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
+            PyErr_SetVim(_("cannot save undo information"));
+        else
+        {
+            for (i = 0; i < size; ++i)
+            {
+                if (ml_append((linenr_T)(n + i),
+                                        (char_u *)array[i], 0, FALSE) == FAIL)
+                {
+                    PyErr_SetVim(_("cannot insert line"));
+
+                    /* Free the rest of the lines */
+                    while (i < size)
+                        vim_free(array[i++]);
+
+                    break;
+                }
+                vim_free(array[i]);
+            }
+            if (i > 0)
+                appended_lines_mark((linenr_T)n, (long)i);
+        }
+
+        /* Free the array of lines. All of its contents have now
+         * been freed.
+         */
+        vim_free(array);
+
+        curbuf = savebuf;
+        update_screen(VALID);
+
+        if (PyErr_Occurred() || VimErrorCheck())
+            return FAIL;
+
+        if (len_change)
+            *len_change = size;
+
+        return OK;
+    }
+    else
+    {
+        PyErr_BadArgument();
+        return FAIL;
+    }
+}
+
+/* Convert a Vim line into a Python string.
+ * All internal newlines are replaced by null characters.
+ *
+ * On errors, the Python exception data is set, and NULL is returned.
+ */
+static PyObject * LineToString(const char *str)
+{
+    PyObject *result;
+    Py_ssize_t len = strlen(str);
+    char *tmp,*p;
+
+    tmp = (char *)alloc((unsigned)(len+1));
+    p = tmp;
+    if (p == NULL)
+    {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    while (*str)
+    {
+        if (*str == '\n')
+            *p = '\0';
+        else
+            *p = *str;
+
+        ++p;
+        ++str;
+    }
+    *p = '\0';
+
+    result = PyUnicode_FromStringAndSize(tmp, len);
+
+    vim_free(tmp);
+    return result;
+}
+
+/* Convert a Python string into a Vim line.
+ *
+ * The result is in allocated memory. All internal nulls are replaced by
+ * newline characters. It is an error for the string to contain newline
+ * characters.
+ *
+ * On errors, the Python exception data is set, and NULL is returned.
+ */
+static char * StringToLine(PyObject *obj)
+{
+    const char *str;
+    char *save;
+    Py_ssize_t len;
+    Py_ssize_t i;
+    char *p;
+
+    if (obj == NULL || !PyUnicode_Check(obj))
+    {
+        PyErr_BadArgument();
+        return NULL;
+    }
+
+    str = _PyUnicode_AsString(obj);
+    len = PyUnicode_GET_SIZE(obj);
+
+    /*
+     * Error checking: String must not contain newlines, as we
+     * are replacing a single line, and we must replace it with
+     * a single line.
+     * A trailing newline is removed, so that append(f.readlines()) works.
+     */
+    p = memchr(str, '\n', len);
+    if (p != NULL)
+    {
+        if (p == str + len - 1)
+            --len;
+        else
+        {
+            PyErr_SetVim(_("string cannot contain newlines"));
+            return NULL;
+        }
+    }
+
+    /* Create a copy of the string, with internal nulls replaced by
+     * newline characters, as is the vim convention.
+     */
+    save = (char *)alloc((unsigned)(len+1));
+    if (save == NULL)
+    {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    for (i = 0; i < len; ++i)
+    {
+        if (str[i] == '\0')
+            save[i] = '\n';
+        else
+            save[i] = str[i];
+    }
+
+    save[i] = '\0';
+
+    return save;
+}
+
+/* Check to see whether a Vim error has been reported, or a keyboard
+ * interrupt has been detected.
+ */
+static int VimErrorCheck(void)
+{
+    if (got_int)
+    {
+        PyErr_SetNone(PyExc_KeyboardInterrupt);
+        return 1;
+    }
+    else if (did_emsg && !PyErr_Occurred())
+    {
+        PyErr_SetNone(VimError);
+        return 1;
+    }
+
+    return 0;
+}
+
+
+static void init_structs(void)
+{
+    vim_memset(&OutputType, 0, sizeof(OutputType));
+    OutputType.tp_name = "vim.message";
+    OutputType.tp_basicsize = sizeof(OutputObject);
+    OutputType.tp_getattro = OutputGetattro;
+    OutputType.tp_setattro = OutputSetattro;
+    OutputType.tp_flags = Py_TPFLAGS_DEFAULT;
+    OutputType.tp_doc = "vim message object";
+    OutputType.tp_methods = OutputMethods;
+    OutputType.tp_alloc = call_PyType_GenericAlloc;
+    OutputType.tp_new = call_PyType_GenericNew;
+    OutputType.tp_free = call_PyObject_Free;
+
+    vim_memset(&BufferType, 0, sizeof(BufferType));
+    BufferType.tp_name = "vim.buffer";
+    BufferType.tp_basicsize = sizeof(BufferType);
+    BufferType.tp_dealloc = BufferDestructor;
+    BufferType.tp_repr = BufferRepr;
+    BufferType.tp_as_sequence = &BufferAsSeq;
+    BufferType.tp_as_mapping = &BufferAsMapping;
+    BufferType.tp_getattro = BufferGetattro;
+    BufferType.tp_flags = Py_TPFLAGS_DEFAULT;
+    BufferType.tp_doc = "vim buffer object";
+    BufferType.tp_methods = BufferMethods;
+    BufferType.tp_alloc = call_PyType_GenericAlloc;
+    BufferType.tp_new = call_PyType_GenericNew;
+    BufferType.tp_free = call_PyObject_Free;
+
+    vim_memset(&BufListType, 0, sizeof(BufListType));
+    BufListType.tp_name = "vim.bufferlist";
+    BufListType.tp_basicsize = sizeof(BufListObject);
+    BufListType.tp_as_sequence = &BufListAsSeq;
+    BufListType.tp_flags = Py_TPFLAGS_DEFAULT;
+    BufferType.tp_doc = "vim buffer list";
+
+    vim_memset(&WinListType, 0, sizeof(WinListType));
+    WinListType.tp_name = "vim.windowlist";
+    WinListType.tp_basicsize = sizeof(WinListType);
+    WinListType.tp_as_sequence = &WinListAsSeq;
+    WinListType.tp_flags = Py_TPFLAGS_DEFAULT;
+    WinListType.tp_doc = "vim window list";
+
+    vim_memset(&RangeType, 0, sizeof(RangeType));
+    RangeType.tp_name = "vim.range";
+    RangeType.tp_basicsize = sizeof(RangeObject);
+    RangeType.tp_dealloc = RangeDestructor;
+    RangeType.tp_repr = RangeRepr;
+    RangeType.tp_as_sequence = &RangeAsSeq;
+    RangeType.tp_as_mapping = &RangeAsMapping;
+    RangeType.tp_getattro = RangeGetattro;
+    RangeType.tp_flags = Py_TPFLAGS_DEFAULT;
+    RangeType.tp_doc = "vim Range object";
+    RangeType.tp_methods = RangeMethods;
+    RangeType.tp_alloc = call_PyType_GenericAlloc;
+    RangeType.tp_new = call_PyType_GenericNew;
+    RangeType.tp_free = call_PyObject_Free;
+
+    vim_memset(&CurrentType, 0, sizeof(CurrentType));
+    CurrentType.tp_name = "vim.currentdata";
+    CurrentType.tp_basicsize = sizeof(CurrentObject);
+    CurrentType.tp_getattro = CurrentGetattro;
+    CurrentType.tp_setattro = CurrentSetattro;
+    CurrentType.tp_flags = Py_TPFLAGS_DEFAULT;
+    CurrentType.tp_doc = "vim current object";
+
+    vim_memset(&vimmodule, 0, sizeof(vimmodule));
+    vimmodule.m_name = "vim";
+    vimmodule.m_doc = vim_module_doc;
+    vimmodule.m_size = -1;
+    vimmodule.m_methods = VimMethods;
+}
--- a/src/main.c
+++ b/src/main.c
@@ -1405,6 +1405,9 @@ getout(exitval)
 #ifdef FEAT_PYTHON
     python_end();
 #endif
+#ifdef FEAT_PYTHON3
+    python3_end();
+#endif
 #ifdef FEAT_PERL
     perl_end();
 #endif
--- a/src/proto.h
+++ b/src/proto.h
@@ -186,6 +186,10 @@ void qsort __ARGS((void *base, size_t el
 #  include "if_python.pro"
 # endif
 
+# ifdef FEAT_PYTHON3
+#  include "if_python3.pro"
+# endif
+
 # ifdef FEAT_TCL
 #  include "if_tcl.pro"
 # endif
new file mode 100644
--- /dev/null
+++ b/src/proto/if_python3.pro
@@ -0,0 +1,8 @@
+/* if_python.c */
+int python3_enabled __ARGS((int verbose));
+void python3_end __ARGS((void));
+void ex_python3 __ARGS((exarg_T *eap));
+void ex_py3file __ARGS((exarg_T *eap));
+void python3_buffer_free __ARGS((buf_T *buf));
+void python3_window_free __ARGS((win_T *win));
+/* vim: set ft=c : */
--- a/src/structs.h
+++ b/src/structs.h
@@ -1612,6 +1612,10 @@ struct file_buffer
     void	*b_python_ref;	/* The Python reference to this buffer */
 #endif
 
+#ifdef FEAT_PYTHON3
+    void	*b_python3_ref;	/* The Python3 reference to this buffer */
+#endif
+
 #ifdef FEAT_TCL
     void	*b_tcl_ref;
 #endif
@@ -2106,6 +2110,10 @@ struct window_S
     void	*w_python_ref;		/* The Python value for this window */
 #endif
 
+#ifdef FEAT_PYTHON3
+    void	*w_python3_ref;		/* The Python value for this window */
+#endif
+
 #ifdef FEAT_TCL
     void	*w_tcl_ref;
 #endif
--- a/src/version.c
+++ b/src/version.c
@@ -474,6 +474,15 @@ static char *(features[]) =
 #else
 	"-python",
 #endif
+#ifdef FEAT_PYTHON3
+# ifdef DYNAMIC_PYTHON3
+	"+python3/dyn",
+# else
+	"+python3",
+# endif
+#else
+	"-python3",
+#endif
 #ifdef FEAT_QUICKFIX
 	"+quickfix",
 #else
--- a/src/vim.h
+++ b/src/vim.h
@@ -13,6 +13,7 @@
 #if defined(__BORLANDC__) && defined(WIN32) && !defined(DEBUG)
 #if defined(FEAT_PERL) || \
     defined(FEAT_PYTHON) || \
+    defined(FEAT_PYTHON3) || \
     defined(FEAT_RUBY) || \
     defined(FEAT_TCL) || \
     defined(FEAT_MZSCHEME) || \
--- a/src/window.c
+++ b/src/window.c
@@ -4386,6 +4386,10 @@ win_free(wp, tp)
     python_window_free(wp);
 #endif
 
+#ifdef FEAT_PYTHON3
+    python3_window_free(wp);
+#endif
+
 #ifdef FEAT_TCL
     tcl_window_free(wp);
 #endif