Как определить оператор, который обновляется, пока он принимает данные?


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

Это должно работать, но выравнивание не выполняется до того, как я нажму клавишу ввода, то есть после того, как я закончу ввод ввода, что фактически означает, что оно работает так же, как неинтерактивная функция. Интересно, могла ли проблема быть чем-то вроде экрана / контента, не обновляющегося во время выполнения оператора, только после.

Любые идеи о том, что проблема может быть оценена!

Ответы:


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, который может делать то, что вы пытаетесь. Вы можете черпать вдохновение из его сценария .


Большое спасибо за ясные объяснения! Я не знал, что easy-align может это сделать. Функциональность отмены была следующей вещью, которую я хотел реализовать, но я застрял в обновлении.
Tusj

Нет проблем 🙂 Я просто обновил ответ, чтобы выделить шаблон, если он содержит ошибку.
Томми А

1
В текущей реализации есть небольшая ошибка из-за неписаного требования: если был напечатан Esc или <CC>, операция должна быть отменена. Я исправил первый случай, добавив: if c == "\<Esc>" && undo silent! undo endif я не уверен, как определить <CC>.
Tusj

@Tusj Я обновил ответ.
Томми А
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.