详解如何使用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支持,直接下载就可以了:
Windows:可以在这里下载。
Mac OS:可以直接brew install vim来安装。
Linux:也有快捷的安装方式,就不赘言了。
2. 如何让Python能正常工作
虽然vim已经支持Python,但是可能:echo has("python")或:echo has("python3")的结果仍是0,说明Python还不能正常工作。
此时需要检查:
系统上是否装了Python?
Python是32位还是64位跟vim是否匹配?
Python的版本跟编译时的版本是否一致(编译时的版本可以使用:version查看)
通过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),返回结果类型为:
string: 如果vim表达式的值的类型是string或number
list:如果vim表达式的值的类型是一个vim list(:h list)
dictionary:如果vim表达式的值的类型是一个vim dictionary(:h dict)
例如:
:py sw = vim.eval("&shiftwidth")
:py print vim.eval("expand('%:p')")
:py print vim.eval("@a")
vim模块还提供了一些有用的对象:
Tabpage对象(:h python-tabpage) 一个Tabpage对象对应vim的一个Tabpage。
Window对象(:h python-window) 一个Window对象对应vim的一个Window。
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.line | The current line (RW) | String |
vim.current.buffer | The current buffer (RW) | Buffer |
vim.current.window | The current window (RW) | Window |
vim.current.tabpage | The current tab page (RW) | TabPage |
vim.current.range | The 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
猜你喜欢
- 代码如下:--创建测试表 DECLARE @Users TABLE ( ID INT IDENTITY(1,1), UserIn
- PHP用代码实现文件下载,阅读PHP用代码实现文件下载,我们一般实现下载都是调用url来下载,但是遇到ie能识别打开的文件就不能用这种方式了
- 长话短说:本人下载 matplotlib 花了大概三个半小时屡屡碰壁,险些暴走。为了不让新来的小伙伴走我的弯路,特意创作本片文章指明方向。1
- 公司做了个客户,需要图片生成像alibaba的效果。原来开发的系统都是用Aspjpeg进行缩小图的,现在需要处理图片,当然又想到这个组件。但
- 也许你刚刚来到一家公司,他们希望进行一些“可用性”工作。你可能是一名UI设计师,业务分析师,或前端开发人员,一名产品经理,或者负责用户体验部
- Tag,直译标签,是一种由用户自定义的、用于描述信息 [1]的关键词。Tagging是用户为信息赋予Tag的行为。Delicious,Fli
- 本文首先介绍在python3中print函数的应用,然后对比在pyhton2中的应用。(本文作者所用版本为3.6.0)首先我们通过help(
- 实际数据分析中遇到需求,把某个Excel表格按照某一列分为多个sheet,并且要求如果某个key对应的行数较少应该合并到一个sheet中。i
- 前言由于笔者近期的研究课题与图像后处理有关,需要通过图像处理工具对图像进行变换和处理,进而生成合适的训练图像数据。该系列文章即主要记录笔者在
- 前言在本文中,我们将介绍一些常见的分布并通过Python 代码进行可视化以直观地显示它们。概率和统计知识是数据科学和机器学习的核心;&nbs
- PHP getNamespaces() 函数实例返回 XML 文档中使用的命名空间:<?php $xml=<<<XM
- 线程线程(Thread),有时也被称为轻量级进程(Lightweight Process,LWP),是操作系 * ⽴调度和分派的基本单位,本质
- 钉钉设置机器人首先在钉钉设置钉钉机器人群设置—> 智能群助手—>添加机器人—>自定义添加完成,得到一个Webhook AP
- 前言使用Python中的自带库math、自带函数pow和自带库cmath来对数字进行开根号运算方法一使用:math.sqrt(数字)impo
- 想想你在一家公司里做表格,现在有一个下面这样的excel表摆在你面前,这是一个员工每个月工资的表,现在假设,你要做的事情,是填充好后面几个月
- 此文档是一位高手同事Hewei的原创实践总结,过程真是精彩,最后修复损坏数据库取得圆满效果,值得收藏的一篇好文章。前几天因为mysql数据库
- 今天来给大家推荐一个Python当中超级好用的内置函数,那便是lambda方法,本篇教程大致和大家分享什么是lambda函数lambda函数
- 本文实例讲述了python实现的分析并统计nginx日志数据功能。分享给大家供大家参考,具体如下:利用python脚本分析nginx日志内容
- 本篇文章起源于在GCR MVP Open Day的时候和C# MVP张响讨论连接池的概念而来的。因此单独写一篇文章剖析一下连接池。 为什么需
- extend()方法追加序列内容到列表。语法以下是extend()方法的语法:list.extend(seq)参数 &