详解如何使用Python编写vim插件

作者:Yggdroot 时间:2023-01-08 13:30:39 

前言

vim是个伟大的编辑器,不仅在于她特立独行的编辑方式,还在于她强大的扩展能力。然而,vim自身用于写插件的语言vimL功能有很大的局限性,实现功能复杂的插件往往力不从心,而且运行效率也不高。幸好,vim早就想到了这一点,她提供了很多外部语言接口,比如Python,ruby,lua,Perl等,可以很方便的编写vim插件。本文主要介绍如何使用Python编写vim插件。

准备工作

1. 编译vim,使vim支持Python

在编译之前,configure的时候加上--enable-pythoninterp和--enable-python3interp选项,使之分别支持Python2和Python3
编译好之后,可以通过vim --version | grep +python来查看是否已经支持Python,结果中应该包含+python和 +python3,当然也可以编译成只支持Python2或Python3。

现在好多平台都有直接编译好的版本,已经包含Python支持,直接下载就可以了:

  1. Windows:可以在这里下载。

  2. Mac OS:可以直接brew install vim来安装。

  3. Linux:也有快捷的安装方式,就不赘言了。

2. 如何让Python能正常工作

虽然vim已经支持Python,但是可能:echo has("python")或:echo has("python3")的结果仍是0,说明Python还不能正常工作。
此时需要检查:

  1. 系统上是否装了Python?

  2. Python是32位还是64位跟vim是否匹配?

  3. Python的版本跟编译时的版本是否一致(编译时的版本可以使用:version查看)

  4. 通过pythondll和pythonthreedll来分别指定Python2和Python3所使用的动态库。

例如,可以在vimrc里添加


set pythondll=/Users/yggdroot/.python2.7.6/lib/libpython2.7.so

经此4步,99%能让Python工作起来,剩下的1%就看人品了。

补充一点:

对于neovim,执行


pip2 install --user --upgrade neovim
pip3 install --user --upgrade neovim

就可以添加Python2和Python3的支持,具体参见:h provider-python。

从hello world开始

在命令行窗口执行:pyx print("hello world!"),输出“hello world!”,说明Python工作正常,此时我们已经可以使用Python来作为vim的EX命令了。

操作vim像vimL一样容易

怎么用Python来访问vim的信息以及操作vim呢?很简单,vim的Python接口提供了一个叫vim的模块(module)。vim模块是Python和vim沟通的桥梁,通过它,Python可以访问vim的一切信息以及操作vim,就像使用vimL一样。所以写脚本,首先要import vim。

vim模块

vim模块提供了两个非常有用的函数接口:

vim.command(str)

执行vim中的命令str(ex-mode),返回值为None,例如:


:py vim.command("%s/\s\+$//g")
:py vim.command("set shiftwidth=4")
:py vim.command("normal! dd")

vim.eval(str)

求vim表达式str的值,(什么是vim表达式,参见:h expr),返回结果类型为:

  1. string: 如果vim表达式的值的类型是string或number

  2. list:如果vim表达式的值的类型是一个vim list(:h list)

  3. dictionary:如果vim表达式的值的类型是一个vim dictionary(:h dict)

例如:


:py sw = vim.eval("&shiftwidth")
:py print vim.eval("expand('%:p')")
:py print vim.eval("@a")

vim模块还提供了一些有用的对象:

  1. Tabpage对象(:h python-tabpage) 一个Tabpage对象对应vim的一个Tabpage。

  2. Window对象(:h python-window) 一个Window对象对应vim的一个Window。

  3. Buffer对象(:h python-buffer) 一个Buffer对象对应vim的一个buffer,Buffer对象提供了一些属性和方法,可以很方便操作buffer。

例如 (假定b是当前的buffer) :


:py print b.name   # write the buffer file name
:py b[0] = "hello!!!"  # replace the top line
:py b[:] = None    # delete the whole buffer
:py del b[:]    # delete the whole buffer
:py b[0:0] = [ "a line" ] # add a line at the top
:py del b[2]    # delete a line (the third)
:py b.append("bottom")  # add a line at the bottom
:py n = len(b)    # number of lines
:py (row,col) = b.mark('a') # named mark
:py r = b.range(1,5)  # a sub-range of the buffer
:py b.vars["foo"] = "bar" # assign b:foo variable
:py b.options["ff"] = "dos" # set fileformat
:py del b.options["ar"]  # same as :set autoread<

vim.current对象(:h python-current)

vim.current对象提供了一些属性,可以方便的访问“当前”的vim对象

属性含义类型
vim.current.lineThe current line (RW)String
vim.current.bufferThe current buffer (RW)Buffer
vim.current.windowThe current window (RW)Window
vim.current.tabpageThe current tab page (RW)TabPage
vim.current.rangeThe current line range (RO)Range

python访问vim中的变量

访问vim中的变量,可以通过前面介绍的vim.eval(str)来访问,例如:


:py print vim.eval("v:version")

但是, 还有更pythonic的方法:

预定义vim变量(v:var)

可以通过vim.vvars来访问预定义vim变量,vim.vvars是个类似Dictionary的对象。例如,访问v:version:


:py print vim.vvars["version"]

全局变量(g:var)

可以通过vim.vars来访问全局变量,vim.vars也是个类似Dictionary的对象。例如,改变全局变量g:global_var的值:


:py vim.vars["global_var"] = 123

tabpage变量(t:var)

例如:


:py vim.current.tabpage.vars["var"] = "Tabpage"

window变量(w:var)

例如:


:py vim.current.window.vars["var"] = "Window"

buffer变量(b:var)

例如:


:py vim.current.buffer.vars["var"] = "Buffer"

python访问vim中的选项(options)

访问vim中的选项,可以通过前面介绍的vim.command(str)和vim.eval(str)来访问,例如:


:py vim.command("set shiftwidth=4")
:py print vim.eval("&shiftwidth")

当然, 还有更pythonic的方法:

全局选项设置(:h python-options)

例如:


:py vim.options["autochdir"] = True

注意:如果是window-local或者buffer-local选项,此种方法会报KeyError异常。对于window-local和buffer-local选项,请往下看。

window-local选项设置

例如:


:py vim.current.window.options["number"] = True

buffer-local选项设置

例如:


:py vim.current.buffer.options["shiftwidth"] = 4

两种方式写vim插件

内嵌式


py[thon] << {endmarker}
{script}
{endmarker}

{script}中的内容为Python代码,{endmarker}是一个标记符号,可以是任何字符串,不过{endmarker}前面不能有任何的空白字符,也就是要顶格写。

例如,写一个函数,打印出当前buffer所有的行(Demo.vim):


function! Demo()
py << EOF
import vim
for line in vim.current.buffer:
print line
EOF
endfunction
call Demo()

运行:source %查看结果。

独立式

把Python代码写到*.py中,vimL只用来定义全局变量、map、command等,LeaderF就是采用这种方式。个人更喜欢这种方式,可以把全部精力集中在写Python代码上。

异步

多线程

可以通过Python的threading模块来实现多线程。但是,线程里面只能实现与vim无关的逻辑,任何试图在线程里面操作vim的行为都可能(也许用“肯定会”更合适)导致vim崩溃,甚至包括只读一个vim选项。虽然如此,也比vimL好多了,毕竟聊胜于无。

subprocess

可以通过Python的subprocess模块来调用外部命令。

例如:


:py import subprocess
:py print subprocess.Popen("ls -l", shell=True, stdout=subprocess.PIPE).stdout.read()

也就是说,从支持Python起,vim就已经支持异步了(虽然直到vim7.4才基本没有bug),Neovim所增加的异步功能,对用Python写插件的小伙伴来说,没有任何吸引力。好多Neovim粉竟以引入异步(job)而引以为傲,它什么时候能引入真正的多线程支持我才会服它。

案例

著名的补全插件YCM和模糊查找神器LeaderF都是使用Python编写的。

缺陷

由于GIL的原因,Python线程无法并行处理;而vim又不支持Python的进程(https://github.com/vim/vim/issues/906),计算密集型任务想利用多核来提高性能已不可能。

奇技淫巧

把buffer中所有单词首字母变为大写字母


:%pydo return line.title()

把buffer中所有的行镜像显示

例如,把


vim is very useful
123 456 789
abc def ghi
who am I

变为


lufesu yrev si miv
987 654 321
ihg fed cba
I ma ohw

可以执行此命令::%pydo return line[::-1]

总结

以上只是简单的介绍,更详细的资料可以参考:h python。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

来源:http://blog.csdn.net/archofortune/article/details/78653853

标签:Python,vim,插件
0
投稿

猜你喜欢

  • Python3.5面向对象编程图文与实例详解

    2023-12-04 23:21:51
  • 浅谈python和C语言混编的几种方式(推荐)

    2021-11-30 02:48:51
  • 使用coverage统计python web项目代码覆盖率的方法详解

    2023-05-23 18:24:35
  • python如何提取xml指定内容

    2021-07-02 01:21:10
  • Oracle数据安全面面观

    2010-07-27 13:27:00
  • Golang的继承模拟实例

    2024-05-08 10:23:14
  • python 执行终端/控制台命令的例子

    2022-11-16 20:41:29
  • Python 的AES加密与解密实现

    2022-07-09 21:49:49
  • python使用py2neo查询Neo4j的节点、关系及路径

    2023-02-01 18:11:52
  • python条件和循环的使用方法

    2021-12-16 22:27:59
  • Python数学建模学习模拟退火算法旅行商问题示例解析

    2023-07-28 08:33:24
  • Python跑循环时内存泄露的解决方法

    2023-07-18 08:18:22
  • Python实现各种邮件发送

    2021-09-01 17:35:47
  • mysql中的mvcc 原理详解

    2024-01-18 05:10:13
  • 用Python实现一本个性化日历

    2021-02-11 08:59:44
  • layui文件上传实现代码

    2024-05-22 10:36:34
  • python3获取控制台输入的数据的具体实例

    2022-05-08 13:49:37
  • 默认Web字体样式

    2009-11-24 12:37:00
  • 深入MySQL数据库的索引

    2009-02-26 15:27:00
  • asp如何读取Windows的信息文件(.ini)?

    2009-11-20 18:27:00
  • asp之家 网络编程 m.aspxhome.com