Як визначити оператора, який оновлюється під час введення даних?


9

Я визначив відображення оператора, який займає область тексту, потім запитує рядок введення, а потім вирівнює область з табличною, використовуючи рядок введення. Це чудово працює.

Я реалізував це так, використовуючи 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, тобто після того, як я закінчую введення вводу, фактично означає, що він працює так само, як і неінтерактивна функція. Цікаво, чи проблема може бути не на зразок того, що екран / вміст не оновлюється під час виконання оператором, лише після.

Будь-яка ідея щодо проблеми, яка може бути оцінена!

Відповіді:


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

Немає проблем 🙂 Я просто оновив відповідь, щоб виділити шаблон, якщо він має помилку.
Tommy A

1
У поточній реалізації є крихітна помилка через не письмову вимогу: якщо Esc або <CC> було введено, операцію слід скасувати. Я виправив перший випадок, додавши: if c == "\<Esc>" && undo silent! undo endif Я не впевнений, як виявити <CC>.
tusj

@tusj Я оновив відповідь.
Tommy A
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.