Lua中Neovim插件的UI

2020-07-21 02:22:09

在上一篇文章中,我们了解了在Lua中使用浮动窗口创建插件的基础知识。现在是时候采用更传统的方法了。让我们创建一个简单的插件,它将在方便的侧边导航中显示上次打开的文件。当我们专注于学习界面时,我们将使用VIM原生旧文件列表来实现此目的。它将如下所示:

如果你没有读过前一篇文章,我强烈建议你读一读,因为这篇文章扩展了上一篇文章的观点,与之相比充满了新的东西。

好的,那么我们应该从编写一个函数开始,该函数将创建我们的第一个窗口,其中将显示旧文件列表。但首先,我们将在脚本的主要作用域中声明三个变量:buf和win,它们将包含导航窗口和缓冲区引用,以及start_win,它们将记住我们打开导航的位置。我们将在我们的插件功能中经常使用这些。

--这是我们的主要启动功能。现在,我们只在这里创建导航窗口。本地函数oldfiles()create_win()end local函数create_win()--我们将句柄保存到打开导航start_win=vim的窗口。接口。Nvim_get_current_win()vim。接口。Nvim_command(';Botright vnew';)--我们在最右边的win=vim处打开一个新的垂直窗口。接口。Nvim_get_current_win()--我们保存导航窗口句柄...。Buf=vim。接口。Nvim_get_current_buf()--...及其缓冲区句柄。--我们应该给我们的缓冲区命名。VIM中的所有缓冲区必须具有唯一的名称。--最简单的解决方案是向其添加缓冲区句柄--因为它已经是唯一的,而且它只是一个数字。维姆。接口。NVIM_BUF_SET_NAME(BUF,';旧文件#';.。Buf)--现在我们为缓冲区设置一些选项。--nofile防止标记缓冲区被修改,因此我们永远不会收到有关未保存更改的警告。--还有一些插件以不同的方式对待非文件缓冲区。--例如,oc.nvim不会触发这些的完成。维姆。接口。Nvim_buf_set_option(buf;buftype';,';nofile';)--我们不需要交换文件。维姆。接口。Nvim_buf_set_option(buf,#39;swapfile';,false)--我们更希望在隐藏时销毁缓冲区。维姆。接口。Nvim_buf_set_option(bufide&39;,';擦除)--这不是必需的,但设置自定义文件类型是很好的做法。--这允许用户在filetype上创建他们自己的自动命令或配色方案。--并防止与其他插件发生冲突。维姆。接口。Nvim_buf_set_option(buf,';filetype';,';nvim-oldfile';)--为了获得更好的用户体验,我们将关闭换行并打开当前行突出显示。维姆。接口。NVIM_WIN_SET_OPTION(WIN,#39;WRAP;,FALSE)VIM。接口。Nvim_win_set_option(win,#39;cursorline';,true)set_mappings()--在结束时,我们将为导航设置映射。端部。

好的,我们有一个窗口,现在我们需要一些东西在里面展示。我们将使用vim oldfiles特殊变量,它存储以前打开的文件的路径。我们将从其中提取尽可能多的项,因为我们可以在不滚动的情况下显示这些项,但是当然,您可以在脚本中提取任意数量的项。我们将调用此函数REDRAW,因为它可用于刷新导航内容。文件路径可能很长,因此我们将尝试使它们相对于工作目录。

本地函数reraw()--首先,我们允许向缓冲区引入新的更改。我们会在最后阻止这一点。维姆。接口。Nvim_buf_set_option(buf,#39;可修改';,true)local item_count=vim。接口。NVIM_WIN_GET_HEIGHT(WIN)-1--获取窗口高度本地列表={}--如果您使用夜间构建,您可以获得类似本地oldfiles=vim的旧文件。v.。Oldfiles--在稳定版本中,只能使用local oldfiles=vim。接口。Nvim_get_vvar(';oldfiles';)--现在我们用来自oldfiles for i=#oldfiles,#oldfiles-item_count,-1 do的X个最后项目填充我们的列表--我们使用内置的vim函数fnamModify使路径成为相对的--在夜间,我们可以调用类似local path=vim的vim函数。Fn.。Fnamemodify(oldfiles[i],';:.';)--这是稳定版本:local path=vim。接口。Nvim_call_function(';fnamemodify';,{oldfiles[i],';:.';})--我们从头到尾迭代,因此应该在结果列表的末尾插入项--以保留顺序表。insert(list,#list+1,path)end--我们将结果应用到缓冲区vim。接口。NVIM_BUF_SET_LINES(buf,0,-1,false,list)--并关闭编辑vim。接口。Nvim_buf_set_option(buf,';可修改';,false)结束。

我们现在可以更新我们的主函数了。我们还将添加一些阻止打开多个导航窗口的代码。为此,我们可以使用nvim_win_is_valid来检查我们的插件窗口是否已经读取

让我们从在当前窗口中打开文件开始。我们应该为两种情况做好准备:1.在用户打开导航的窗口中打开文件。2.关闭启动窗口,此时我们将新建一个打开文件的窗口。

Local function open()--我们从用户在local path=vim上按回车的行获得路径。接口。NVIM_GET_CURRENT_LINE()--如果VIM,则启动窗口是否存在。接口。NVIM_WIN_IS_VALID(START_WIN)然后--我们转到VIM。接口。NVIM_SET_CURRENT_WIN(START_WIN)--并编辑所选文件VIM。接口。Nvim_command(';编辑';..。Path)否则--如果没有起始窗口,我们将从最前面的vim创建新窗口。接口。Nvim_command(';leftover vplit';.。Path)--并将其设置为新的起始窗口start_win=vim。接口。Nvim_get_current_win()end end--打开所需文件后,用户不再需要我们的导航--因此我们应该创建函数来关闭它。如果WIN和VIM,则局部函数Close()。接口。NVIM_WIN_IS_VALID(WIN),然后是VIM。接口。NVIM_WIN_CLOSE(WIN,TRUE)END END--OK。现在,我们已经准备好使两个第一个打开函数本地函数open_和_close()open()--我们打开新文件close()--关闭导航结束本地函数review()open()--我们打开新文件--但是在预览中,我们不关闭导航--我们将焦点放回VIM。接口。NVIM_SET_CURRENT_WIN(WIN)结束。

--要进行拆分,我们只需要一个函数LOCAL Function SPLIT(轴)LOCAL PATH=VIM。接口。NVIM_GET_CURRENT_LINE()--如果是VIM,我们仍然需要处理两种情况。接口。NVIM_WIN_IS_VALID(START_WIN)然后是VIM。接口。NVIM_SET_CURRENT_WIN(START_WIN)--如果需要垂直拆分,则在轴参数中传递v--否则不传递任何内容/空字符串。维姆。接口。Nvim_command(轴..。拆分';..。Path)否则--如果没有开始窗口,我们将在左侧vim上创建新窗口。接口。Nvim_command(';left上方';.。轴心..。拆分';..。Path)--但在本例中我们不需要设置新的起始窗口--因为拆分总是关闭导航结束close()end。

要使一切正常工作,我们需要添加键映射,导出所有公共函数,并添加一个命令来触发我们的导航。

本地函数set_mappings()local mappings={q=';Close()';,[';<;cr>;';]=';open_and_close()';,v=';Split(";v";)';,s=';Split(";";)';,p=';Preview()';,t=';open_in_tab()';}对于k,v成对(映射)执行--让';假设我们的脚本在lua/nvim-oldfile.lua文件中。维姆。接口。Nvim_buf_set_keymap(buf,';n';,k,';:lua要求";nvim-oldfile";.';.。V..。';<;cr>;';,{noWait=true,noremap=true,Silent=true})end end--在文件结束时返回{oldfiles=oldfiles,close=close,open_and_close=open_and_close,PREVIEW=PREVIEW,open_in_tab=open_in_tab,Split=Split}。

LOCAL BUF,WIN,START_WIN LOCAL函数OPEN()LOCAL PATH=vim。接口。如果是vim,则为nvim_get_current_line()。接口。NVIM_WIN_IS_VALID(START_WIN)然后是VIM。接口。Nvim_set_current_win(Start_Win)vim。接口。Nvim_command(';编辑';..。路径)其他VIM。接口。Nvim_command(';leftover vplit';.。Path)start_win=vim。接口。如果是WIN和VIM,则使用NVIM_GET_CURRENT_WIN()END END LOCAL Function Close()。接口。NVIM_WIN_IS_VALID(WIN),然后是VIM。接口。NVIM_WIN_CLOSE(win,true)END END LOCAL Function OPEN_AND_CLOSE()open()Close()END LOCAL Function PREVIEW()open()vim。接口。NVIM_SET_CURRENT_WIN(WIN)结束本地函数SPLIT(轴)LOCAL PATH=VIM。接口。如果是vim,则为nvim_get_current_line()。接口。NVIM_WIN_IS_VALID(START_WIN)然后是VIM。接口。Nvim_set_current_win(Start_Win)vim。接口。Nvim_command(轴..。拆分';..。路径)其他VIM。接口。Nvim_command(';left上方';.。轴心..。拆分';..。Path)end close()end local函数open_in_tab()local path=vim。接口。Nvim_get_current_line()vim。接口。Nvim_command(';tabnew';.。Path)close()结束本地函数reraw()vim。接口。Nvim_buf_set_option(buf,#39;可修改';,true)local item_count=vim。接口。NVIM_WIN_GET_HEIGHT(WIN)-1本地列表={}本地旧文件=vim。接口。对于i=#oldfiles,#oldfiles-item_count,-1 do pcall(function()local path=vim)的nvim_get_vvar(';oldfiles';)。接口。Nvim_call_function(';fnamemodify';,{oldfiles[i],';:.';})table.insert(list,#list+1,path)end vim。接口。NVIM_BUF_SET_LINES(buf,0,-1,false,list)vim。接口。Nvim_buf_set_option(buf,';可修改';,false)结束本地函数set_