如何定义一个在输入时正在更新的运算符?


9

我已经定义了一个运算符映射,该映射使用文本区域,然后要求输入字符串,然后使用输入字符串作为参数将区域与Tabular对齐。效果很好。

我已经这样实现了,使用vim-operator-user来帮助定义一个新的运算符:

map \aa <Plug>(operator-align)
call operator#user#define('align', 'Align')
function! Align(motion_wiseness)
    let expr = input("align: ")
    if len(expr) != 0
        execute "'[,']Tabularize /".expr
    endif
endfunction


function! Getchar()
    let c = getchar()
    if c =~ '^\d\+$'
        let c = nr2char(c)
    endif
    return c
endfunction

然后我想知道是否可以在输入要与之对齐的正则表达式时动态更新它。当前方法的问题是,如果使用的表达式不正确,则必须先撤消然后重做。

对于交互式尝试,我这样做:

map \== <Plug>(operator-align-interactive)
call operator#user#define('align-interactive', 'AlignInteractive')
function! AlignInteractive(motion_wiseness)
    let prompt = "Align: "
    echon prompt
    let expr = ""
    let c = Getchar()
     " CR has to be checked for separately as it acts as putting the cursor back to zero position
    while c != "\<Esc>" && c != "\<CR>"
        if c == "\<BS>"
            if len(expr) != 0
                let expr = expr[0:-2]
                echon "\<CR>".substitute(expr, ".", " ", "g")
                echon "\<CR>".prompt.expr
            endif
        else
            let expr .= c
            echon c
            let cmd = "'[,']Tabularize /".expr
            execute cmd 
        endif
        let c = Getchar()
    endwhile
endfunction

应该可以工作,但是在我按Enter键之前,即在我完成输入之后才完成对齐,这实际上意味着它的工作方式与非交互式功能相同。我想知道问题是否出在操作员执行之后,仅在之后才更新屏幕/内容。

任何关于什么问题可以解决的想法表示赞赏!

Answers:


8

您需要undo并且redraw如果您想立即查看缓冲区中的更改。

这是有效的方法:

function! AlignInteractive(motion_wiseness)
  let prompt = "Align: "
  let undo = 0
  let expr = ""
  let range = line("'[").','.line("']")
  let failed = 0
  let accept = 0

  echon prompt
  let c = Getchar()

  while c != "\<Esc>" && c != "\<c-c>"
    let undo = len(expr)

    if c == "\<CR>"
      let accept = 1
      break
    elseif c == "\<BS>"
      if len(expr)
        let expr = expr[0:-2]
      endif
    else
      let expr .= c
    endif

    if undo && !failed
      silent! undo
    endif

    if len(expr)
      try
        call match('', expr)
        let failed = 0
        execute range."Tabularize /".expr
      catch //
        let failed = 1
      endtry
    endif

    redraw

    echon prompt
    if failed
      echohl ErrorMsg
    endif
    echon expr
    echohl None
    let c = Getchar()
  endwhile

  if !accept && len(expr) && !failed
    silent! undo
  endif
endfunction

说明

range变量存储'[']标记。这是出于理智。

undo根据的前一个长度设置称为的变量expr。这意味着无论何时有用户输入,下一次迭代都可以在执行之前安全地撤消Tabularize

call match('', expr)测试表达式的模式错误。如果失败,则undo不应执行。输入诸如的原子时,模式故障可能发生\zs

redraw将清除命令行。这就是为什么在每次迭代时都打印完整提示的原因。

如果模式包含错误,则用突出显示ErrorMsg

accept<cr>按下时设置。如果为假,请撤消更改(如果有)。破坏循环的其他任何事情都会取消。

现有插件

有一个名为vim-easy-align的插件可以完成您要尝试的操作。您可以从脚本中汲取灵感


非常感谢您的明确解释!我不知道容易调整可以做到这一点。撤消功能是我要实现的下一件事,但是我被更新所困。
tusj

没问题🙂如果有错误,我只是更新了答案以突出显示模式。
汤米

1
由于没有书面要求,当前实现中存在一个小错误:如果已键入Esc或<CC>,则应取消该操作。我通过添加以下方法解决了第一种情况:if c == "\<Esc>" && undo silent! undo endif 我不确定如何检测<CC>。
tusj

@tusj我更新了答案。
汤米
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.