我如何 运行 对 select 模板中的新创建文件的一些命令 vim?

how can I run some commands to select template for new created file in vim?

我是 vim 的新手,想了解有关模板的一些有趣功能。现在我有一个 c 模板,在我的 vimrc:

if has("autocmd")
    augroup templates
        autocmd BufNewFile *.c 0r ~/.vim/templates/skeleton.c
    augroup END
endif

但是,我不想用这个模板打开每个 c 文件(也许我有很多不同 c 文件的模板),并且想要在不同模板之间使用一些命令 select。如何实现这个目标?非常感谢!

让我们从需求列表开始:

  • 每次我们编辑一个新的 C 文件时,我们想要...
  • 插入模板…
  • 从列表中选择...
  • 根据特定目录的内容构建。

让我们从下往上做。

目录布局

~/.vim/templates/skeleton.<extension> 允许我们为给定的扩展设置多个“骨架”。我倾向于更喜欢基于文件类型做事,但在这种情况下扩展名更有意义,所以我们将保留您的布局。

列出给定目录中的文件

每当我们需要内置函数时,我们的第一站应该是 :help function-list,它按主题对每个内置函数进行分组,或者如果我们熟悉该分组,则直接 :help <topic>-functions .在这种情况下,我们在 :help file-function 下找到以下行:

readdir()               get a List of file names in a directory

的确,:help readdir() 正是我们所需要的,但不幸的是(而且未记录)它不会自行扩展环境变量或波浪号,因此我们必须 :help expand() 我们的目录路径.

我们可以做到:

:let templates = readdir(expand('~/.vim/templates/'))
:echo templates

得到类似的东西:

['foo.c', 'bar.c', 'baz.h']

或者我们只能 return 扩展名为 .c 的文件:

:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.c$'})
:echo templates
['foo.c', 'bar.c']

或者我们可以使用与当前缓冲区关联的文件的扩展名:

:let templates readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:echo templates
['foo.c', 'bar.c']

完成。

Select 来自列表

我们再次转向 Vim 寻找线索。在 :help interactive-functions 下,我们发现以下有前途的函数:

inputlist()     let the user pick an entry from a list

首先,让我们认识一下:help inputlist()

:echo inputlist(['Choose:', '1. foo', '2. bar', '3. baz'])

看起来像:

Choose:
1. foo
2. bar
3. baz
Type number and <Enter> or click with the mouse (q or empty cancels):

并打印所选数字。

让我们使用之前的文件列表命令让它更有用:

:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:echo inputlist(['Choose a template:'] + templates)

看起来像:

Choose a template:
bar.c
foo.c
Type number and <Enter> or click with the mouse (q or empty cancels):

并且仍然打印所选的数字,但我们在每次输入之前没有数字。这可以用 :help mapnew():

来解决
:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
:echo inputlist(['Choose a template:'] + templates_for_display)

看起来像:

Choose a template:
1. bar.c
2. foo.c
Type number and <Enter> or click with the mouse (q or empty cancels):

并且仍然打印所选的数字。这个阶段剩下的就是打印 templates 中的实际项目。由于列表是从零开始的,我们必须偏移一个以获得直观的显示,我们只需要将 return 由 inputlist():

编辑的数字减去 1
:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
:let choice = inputlist(['Choose a template:'] + templates_for_display)
:echo templates[choice - 1]

正确打印 bar.cfoo.c.

我们正在取得巨大进步!

插入模板

:help :read 是一种从外部源插入文本的粗略方法。在这里,我们更喜欢使用 :help setline():help readfile().

的更简洁的方式

但首先,让我们根据所选模板名称构建完整路径:

:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
:let choice = inputlist(['Choose a template:'] + templates_for_display)
:let chosen_template = expand('~/.vim/templates/' . templates[choice - 1])
:echo chosen_template

应该打印如下内容:

~/.vim/templates/foo.c

我们现在可以读取文件了:

:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
:let choice = inputlist(['Choose a template:'] + templates_for_display)
:let chosen_template = expand('~/.vim/templates/' . templates[choice - 1])
:let template_content = readfile(chosen_template)
:echo template_content

最后,将其插入缓冲区:

:let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
:let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
:let choice = inputlist(['Choose a template:'] + templates_for_display)
:let chosen_template = expand('~/.vim/templates/' . templates[choice - 1])
:let template_content = readfile(chosen_template)
:call setline(1, template_content)

让我们将它们放在我们 vimrc:

中的一个函数中
function SelectTemplate()
    let templates = readdir(expand('~/.vim/templates/'), {name -> name =~ '.' . expand('%:e') . '$'})
    let templates_for_display = templates->mapnew({idx, val -> 1 + idx . '. ' . val})
    let choice = inputlist(['Choose a template:'] + templates_for_display)
    let chosen_template = expand('~/.vim/templates/' . templates[choice - 1])
    let template_content = readfile(chosen_template)
    call setline(1, template_content)
endfunction

并从 c 文件中测试它:

:call SelectTemplate()

太棒了!我们快完成了!

自动化

对于最后一步,我们可以简单地使用您的代码段并进行一些小改动:

if has("autocmd")
    augroup templates
        autocmd!
        autocmd BufNewFile *.c call SelectTemplate()
    augroup END
endif

呸!多么美妙的旅程!

什么,现在?

  • 可以通过删除重复项并在各处添加检查来稍微改进该函数。
  • 这应该可以在自动命令中使用 * 以便它适用于任何文件扩展名。