입력하는 동안 업데이트되는 연산자를 정의하는 방법은 무엇입니까?


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

그것은 작동 해야 하지만 입력을 누르기 전에, 즉 입력 입력을 마친 후에 정렬이 수행되지 않습니다. 비 대화식 기능과 동일한 방식으로 작동한다는 것을 의미합니다. 문제가 운영자 실행 중에 업데이트되지 않은 화면 / 내용과 같은 것일 수 있는지 궁금합니다.

문제가 무엇인지에 대한 아이디어는 높이 평가됩니다!

답변:


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 2016 년

문제 없음 🙂 패턴에 오류가 있으면 강조 표시하도록 답변을 업데이트했습니다.
Tommy A

1
작성되지 않은 요구 사항으로 인해 현재 구현에는 작은 버그가 있습니다. Esc 또는 <CC>를 입력 한 경우 작업을 취소해야합니다. 다음을 추가하여 첫 번째 사례를 수정했습니다 if c == "\<Esc>" && undo silent! undo endif . <CC>를 감지하는 방법을 잘 모르겠습니다.
tusj

@tusj 나는 대답을 업데이트했습니다.
Tommy A
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.