靠 Vim 写 Jekyll 博客已经很久了,编写代码块(Code Fence)时键入前后的```, 以及手动编写文章头信息(Front Matter)一直是个麻烦的事情。 今天就通过Vim键盘映射来对这两种语法提供回车展开支持。最终效果如下:

键入Code Fence```以及高亮语言(|表示光标所在位置):

```javascript|```

此时键入回车:

```javascript
|
```

定界符匹配

Markdown中有两种代码语法:行内代码`foo`,以及用```分隔的代码块(Code Fence)。 我们在输入`时希望Vim自动补全后一个`且光标仍位于两者之间。 要实现这一点需要先安装 delimitMate 插件:

Plugin 'Raimondi/delimitMate'

如何安装Vim插件?请参考打造前端开发的 Vim 环境一文。

然后在~/.vim/after/ftplugin/markdown.vim(不存在则创建该路径及文件)中为Markdown文件配置特殊的`定界符:

let b:delimitMate_quotes = "\" ' `"
let b:delimitMate_nesting_quotes = ['`']

设置`允许嵌套是为了在输入三个`时Vim仍然可以正确匹配。

现在打开一个*.md文件并键入```后,即可自动补全后面的```

```|```

此时敲回车:

```
|```

而我们希望的是:

```
|
```

这便是我们下一节讨论的回车符展开。

回车符展开

本节中更改的还是~/.vim/after/ftplugin/markdown.vim文件, 该文件为Markdown类型文件独有的配置,不会影响其他类型的文件。 首先创建一个键盘映射:将回车映射为Expander()函数调用。

Vim通过文件后缀来识别文件类型,只需要在~/.vimrc中打开该功能::filetype on。 如果你希望自定义文件类型,可以在~/.vim/after/filetype.vim中添加文件类型识别规则。 参见:http://vim.wikia.com/wiki/Filetype.vim

inoremap <expr> <CR> Expander()

其中inoremap是指insert模式(i)下进行映射;且为非递归(nore)映射,即映射后的结果不被再次映射;<CR>为回车符(Carriage Return)。 现在到了程序员的强项:编写Expander函数。

function! Expander()
  let line   = getline(".")
  let col    = col(".") - 1

  if line[0:2] ==# "```" && line[col : col+2] ==# "```"
    return "\<CR>\<Esc>O"
  endif

  return "\<CR>"
endfunction

该函数获取了当前光标所在行内容,以及光标所在位置(敲击回车后光标后移了一格)。 光标后有三个`并且行首也有三个`时返回『回车、退出插入模式、向上插入新行』; 否则返回正常的『回车』。

注意<expr>键盘映射的函数返回值中,按键需要转义。例如\<CR>

头信息展开

在编写Jekyll文章时,首先要编写头信息(Front Matter):

---
title: xxx
tags: tag1 tag2
---

我希望输入---后回车便自动补全以上内容,可以继续修改上述Expander函数:

function! Expander()
  let line   = getline(".")
  let col    = col(".") - 1

  if line[0:2] ==# "```" && line[col : col+2] ==# "```"
    return "\<CR>\<Esc>O"
  endif

  if line[0:2] ==# "---"
    return "\<CR>layout: blog\<CR>---\<Esc>Otitle: "
  endif

  return "\<CR>"
endfunction

保存该文件并重新打开一个*.md文件,输入以下内容(|为光标位置):

---|

按下回车,便可补全Front Matter:

---
layout: blog
title: |
---

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2016/08/05/vim-markdown-cr-expansion.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。