vim括号自动补全

Vim脚本括号自动完成的实现与加强

括号是编程中最常接触的特殊符,因其往往成对出现,成对删除的特性,加上Vim强大的自定义功能,实现括号的自动完成,成对删除等各种功能,大大减少了编程手指负担。本文介绍如何对小括号进行设计达到上述功能,加深对Vim脚本的理解。

一、括号自动完成与加强

1. 括号自动完成
功能描述:当输入(时自动生成(),并使光标指向),系统保持在insert mode
分析:当键入(时,只需模拟输入()并使光标回退一个字符即可
代码1:
inoremap ( ()<LEFT>
2. 重复键入括号自动换行
功能描述:在目标一的基础上实现若光标前一字符为(,则自动换行并缩进,而非插入括号
分析:要达到该效果,必需通过命令实现,调用命令有<C-O>,<ESC>, <C-R>三种途径
<C-O>对于eol与普通字符的处理方式不一样,所以这里采取ESC进入normal模式,<ESC>离开Insert模式恒回退一个字符
代码2:功能一的命令版
function! ParenOpen()
  normal! a()
  startinsert
endfunction
inoremap ( <ESC>:call ParenOpen()<CR>
分析 2:要获得当前光标下的字符,vim似乎没有直接提供命令。但可以通过yl,或者getline('.')[col('.')-1]取得
代码 3:实现功能2
function! ParenOpen()
  let line = getline('.')
  let prev_char = line[col('.')-1]

  if prev_char == '('
    " 添加额外的字符;,以避免vim自动删除空白行
    execute "normal! a\<CR>\<ESC>==O;"
    return
  end

  " 同样需要添加;
  execute "normal! a(;)\<ESC>i"

  "当缩进被删除时,重新缩进当前行
  if line == ''
    normal! ==$h
  end
endfunction

inoremap ( <ESC>:call ParenOpen()<CR>"_cl
3. 忽略重复键入的右括号
功能描术:若当前字符为),则忽略输入的),光标指向下一字符
代码4
function! ParenClose()
  let line = getline('.')
  let char = line[col('.')]

  if char == ')'
    execute "normal! l"
  else
    normal! a)
  end
endfunction
inoremap ) <ESC>:call ParenClose()<CR>a
4. 配对删除括号
功能描述:当删除(时,若()之间为空时,则连)一起删除
分析:目前只能想到map <BS> 一条途径,通过正则判断括号间是否为空
代码5
function! ParenDelete()
  let line = getline('.')
  let prev_char = line[col('.')-1]

  if prev_char == '(' && match(line,'^\s*)',col('.')) != -1
    " 使用 cf) 代替df)使光标离开normal时左移一格用以a
    normal! cf)
  else
    execute "normal! a\<BS>"
  end
endfunction

inoremap <BS> <ESC>:call ParenDelete()<CR>a

二、代码总览:

function! ParenOpen()
  let line = getline('.')
  let prev_char = line[col('.')-1]

  if prev_char == '('
    " 添加额外的字符;,以避免vim自动删除空白行
    execute "normal! a\<CR>\<ESC>==O;"
    return
  end

  " 同样需要添加;
  execute "normal! a(;)\<ESC>i"

  "当缩进被删除时,重新缩进当前行
  if line == ''
    normal! ==$h
  end
endfunction

function! ParenClose()
  let line = getline('.')
  let current_char = line[col('.')]

  if current_char == ')'
    execute "normal! l"
  else
    normal! a)
  end
endfunction

function! ParenDelete()
  let line = getline('.')
  let prev_char = line[col('.')-1]

  if prev_char == '(' && match(line,'^\s*)',col('.')) != -1
    " 使用 cf) 代替df)使光标离开normal时左移一格用以a
    normal! cf)
  else
    execute "normal! a\<BS>"
  end
endfunction

" 函数ParenOpen执行后光标指向;,使用"_cl清除并进入insert模式
inoremap ( <ESC>:call ParenOpen()<CR>"_cl
inoremap ) <ESC>:call ParenClose()<CR>a
inoremap <BS> <ESC>:call ParenDelete()<CR>a

三、使用<C-R>代替<ESC>

<ESC>调用时会导致状态栏,-- 插入 -- 闪烁,修正代码为使用<C-R>代替<ESC>
通过与=表达式寄存器实现括号的自动完成功能{/text}
脚本正好可以不进入Normal模式,如果函数中有normal xxx,那么不得不使用<ESC>作为入口了
function! ParenOpen()
  let line = getline('.')
  let prev_char = line[col('.')-2]

  if prev_char == '('
    return "\<CR>\<ESC>==O"
  end

  return "()\<Left>"
endfunction

function! ParenClose()
  let line = getline('.')
  let current_char = line[col('.')-1]

  if current_char == ')'
    return "\<Right>"
  end
  return ')'
endfunction

function! ParenDelete()
  let line = getline('.')
  let prev_char = line[col('.')-2]

  if prev_char == '(' && match(line,'^\s*)',col('.')-1) != -1
    return "\<Left>\<C-O>cf)"
  end

  return "\<BS>"
endfunction

inoremap <silent> ( <C-R>=ParenOpen()<CR>
inoremap <silent> ) <C-R>=ParenClose()<CR>
inoremap <silent> <BS> <C-R>=ParenDelete()<CR>

四、Vim插件Auto Pairs

Auto Pairs是根据此文进一步完善的插件。支持[]{}() ' "的括号自动完成与删除。
详见: https://github.com/jiangmiao/auto-pairs


2011-06-11更新
-------------------
inoremap X <C-R>=foo()<CR> 可以用inoremap <expr> X<CR>代替
即上文可以改进为
inoremap <silent> <expr> ( ParenOpen()
inoremap <silent> <expr> ) ParenClose()
inoremap <silent> <expr> <BS> ParenDelete()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值