Hoàn thành năng động


12

Tôi đang cố gắng nâng cao chức năng hoàn thành cũ. Tôi muốn cập nhật các lựa chọn được hiển thị trong menu bật lên khi tôi nhập các ký tự mới

Chức năng hoàn thành của tôi là

function! lh#icomplete#ecm(findstart, base) abort
  if a:findstart
    let l = getline('.')
    let startcol = match(l[0:col('.')-1], '\v\S+$')
    if startcol == -1
      let startcol = col('.')-1
    endif
    " let g:debug+= ["findstart(".a:base.") -> ".(startcol)]
    return startcol
  else
    " let g:debug += ["matching(".a:base.")"]
    let words = ['un', 'deux', 'trois', 'trente-deux', 'unité']
    call filter(words, 'v:val =~ a:base')
    " return { 'words' : words}
    return { 'words' : words, 'refresh' : 'always'}
  endif
endfunction

Mà tôi sử dụng với

:set completefunc=lh#icomplete#ecm
:inoremap µ <c-x><c-u><c-p>

Từ sự hiểu biết của tôi về các tài liệu, thực tế tôi sử dụng <c-p>, tôi đi vào trạng thái thứ ba (theo | in-hoàn-menu |), và khi tôi gõ "bất kỳ có thể in được nhân vật, không phải da trắng" Tôi sẽ có thể "Add nhân vật này và giảm số lượng trận đấu. "

Khi tôi nhập vào chế độ chèn , menu hoàn thành sẽ bật lên như mong đợi. Than ôi khi tôi gõ x(ngay sau khi µ), tôi đã thoát khỏi chế độ hoàn thành và uxlà những gì tôi nhận được trong bộ đệm của mình.

Tôi đã làm gì sai hoặc bỏ lỡ trong tài liệu?

Lưu ý: Tôi đã thấy rằng không có refresh=always, kết quả sẽ được lọc, ngoại trừ tôi muốn gọi lại chức năng để áp dụng bộ lọc tùy chỉnh.

(Chỉ trong trường hợp, tôi đang sử dụng gvim 7.4-908)


Điều này có vẻ như một lỗi. Nó cũng không hoạt động với tôi (Tôi đang sử dụng Vim 7.4.944).
Karl Yngve Lervåg

Có nên làm việc không? Đó là những gì tôi không biết.
Luc Hermitte

Các tài liệu dường như ngụ ý rằng nó nên hoạt động.
Karl Yngve Lervåg

Câu trả lời:


3

Sau khi điều tra thêm (và một số kỹ thuật đảo ngược).

Tôi không thể giải thích tại sao hoàn thành không tuân thủ nghiêm ngặt các tài liệu. Tôi sẽ phải hỏi trên vim_dev tôi đoán.

Dù sao, có vẻ như cách để thực hiện nó bao gồm việc đăng ký một người nghe trên CursorMovedIđó sẽ kích hoạt hoàn thành một lần nữa mỗi khi một ký tự được chèn vào.

Khó khăn là sau đó biết khi nào nên dừng lại.

  • CompletionDone không được sử dụng vì nó sẽ được kích hoạt sau mỗi lần nhấn phím.
  • InsertLeave là một khởi đầu tốt, nhưng nó không bao gồm tất cả các trường hợp, tức là
    • Khi một ký tự không còn khớp nào được nhập, chúng ta phải dừng lại
    • Khi người dùng cuối chọn một mục menu, chúng ta cũng phải dừng lại.
      Tôi không tìm thấy cách nào khác ngoài việc ghi đè <cr>, và <c-y>.

Những khó khăn khác bao gồm phát hiện khi không có gì thay đổi để tránh các vòng lặp vô hạn, v.v.

Dù sao đi nữa, đây là mã hiện tại của tôi (sẽ được sử dụng trong các plugin khác). Các phiên bản cuối cùng sẽ được duy trì ở đây . Nó khá dài, nhưng đây là:

" ## Smart completion {{{2
" Function: lh#icomplete#new(startcol, matches, hook) {{{3
function! lh#icomplete#new(startcol, matches, hook) abort
  silent! unlet b:complete_data
  let augroup = 'IComplete'.bufnr('%').'Done'
  let b:complete_data = lh#on#exit()
        \.restore('&completefunc')
        \.restore('&complete')
        \.restore('&omnifunc')
        \.register('au! '.augroup)
        \.register('call self.logger.log("finalized! (".getline(".").")")')
  set complete=
  let b:complete_data.startcol        = a:startcol
  let b:complete_data.all_matches     = map(copy(a:matches), 'type(v:val)==type({}) ? v:val : {"word": v:val}')
  let b:complete_data.matches         = {'words': [], 'refresh': 'always'}
  let b:complete_data.hook            = a:hook
  let b:complete_data.cursor_pos      = []
  let b:complete_data.last_content    = [line('.'), getline('.')]
  let b:complete_data.no_more_matches = 0
  let b:complete_data.logger          = s:logger.reset()

  " keybindings {{{4
  call b:complete_data
        \.restore_buffer_mapping('<cr>', 'i')
        \.restore_buffer_mapping('<c-y>', 'i')
        \.restore_buffer_mapping('<esc>', 'i')
        \.restore_buffer_mapping('<tab>', 'i')
  inoremap <buffer> <silent> <cr>  <c-y><c-\><c-n>:call b:complete_data.conclude()<cr>
  inoremap <buffer> <silent> <c-y> <c-y><c-\><c-n>:call b:complete_data.conclude()<cr>
  " Unlike usual <tab> behaviour, this time, <tab> inserts the next match
  inoremap <buffer> <silent> <tab> <down><c-y><c-\><c-n>:call b:complete_data.conclude()<cr>
  " <c-o><Nop> doesn't work as expected...
  " To stay in INSERT-mode:
  " inoremap <silent> <esc> <c-e><c-o>:<cr>
  " To return into NORMAL-mode:
  inoremap <buffer> <silent> <esc> <c-e><esc>
  " TODO: see to have <Left>, <Right>, <Home>, <End> abort

  " Group {{{4
  exe 'augroup '.augroup
    au!
    " Emulate InsertCharPost
    " au CompleteDone <buffer> call b:complete_data.logger.log("Completion done")
    au InsertLeave  <buffer> call b:complete_data.finalize()
    au CursorMovedI <buffer> call b:complete_data.cursor_moved()
  augroup END

  function! s:cursor_moved() abort dict "{{{4
    if self.no_more_matches
      call self.finalize()
      return
    endif
    if !self.has_text_changed_since_last_move()
      call s:logger.log(lh#fmt#printf("cursor %1 just moved (text hasn't changed)", string(getpos('.'))))
      return
    endif
    call s:logger.log(lh#fmt#printf('cursor moved %1 and text has changed -> relaunch completion', string(getpos('.'))))
    call feedkeys( "\<C-X>\<C-O>\<C-P>\<Down>", 'n' )
  endfunction
  let b:complete_data.cursor_moved = function('s:cursor_moved')

  function! s:has_text_changed_since_last_move() abort dict "{{{4
    let l = line('.')
    let line = getline('.')
    try
      if l != self.last_content[0]  " moved vertically
        let self.no_more_matches = 1
        call s:logger.log("Vertical move => stop")
        return 0
        " We shall leave complete mode now!
      endif
      call s:logger.log(lh#fmt#printf("line was: %1, and becomes: %2; has_changed?%3", self.last_content[1], line, line != self.last_content[1]))
      return line != self.last_content[1] " text changed
    finally
      let self.last_content = [l, line]
    endtry
  endfunction
  let b:complete_data.has_text_changed_since_last_move = function('s:has_text_changed_since_last_move')

  function! s:complete(findstart, base) abort dict "{{{4
    call s:logger.log(lh#fmt#printf('findstart?%1 -> %2', a:findstart, a:base))
    if a:findstart
      if self.no_more_matches
        call s:logger.log("no more matches -> -3")
        return -3
        call self.finalize()
      endif
      if self.cursor_pos == getcurpos()
        call s:logger.log("cursor hasn't moved -> -2")
        return -2
      endif
      let self.cursor_pos = getcurpos()
      return self.startcol
    else
      return self.get_completions(a:base)
    endif
  endfunction
  let b:complete_data.complete = function('s:complete')

  function! s:get_completions(base) abort dict "{{{4
    let matching = filter(copy(self.all_matches), 'v:val.word =~ join(split(a:base, ".\\zs"), ".*")')
    let self.matches.words = matching
    call s:logger.log(lh#fmt#printf("'%1' matches: %2", a:base, string(self.matches)))
    if empty(self.matches.words)
      call s:logger.log("No more matches...")
      let self.no_more_matches = 1
    endif
    return self.matches
  endfunction
  let b:complete_data.get_completions = function('s:get_completions')

  function! s:conclude() abort dict " {{{4
    let selection = getline('.')[self.startcol : col('.')-1]
    call s:logger.log("Successful selection of <".selection.">")
    if !empty(self.hook)
      call lh#function#execute(self.hook, selection)
    endif
    " call self.hook()
    call self.finalize()
  endfunction
  let b:complete_data.conclude = function('s:conclude')

  " Register {{{4
  " call b:complete_data
        " \.restore('b:complete_data')
  " set completefunc=lh#icomplete#func
  set omnifunc=lh#icomplete#func
endfunction

" Function: lh#icomplete#new_on(pattern, matches, hook) {{{3
function! lh#icomplete#new_on(pattern, matches, hook) abort
  let l = getline('.')
  let startcol = match(l[0:col('.')-1], '\v'.a:pattern.'+$')
  if startcol == -1
    let startcol = col('.')-1
  endif
  call lh#icomplete#new(startcol, a:matches, a:hook)
endfunction

" Function: lh#icomplete#func(startcol, base) {{{3
function! lh#icomplete#func(findstart, base) abort
  return b:complete_data.complete(a:findstart, a:base)
endfunction

Mà có thể được sử dụng với:

let entries = [
  \ {'word': 'un', 'menu': 1},
  \ {'word': 'deux', 'menu': 2},
  \ {'word': 'trois', 'menu': 3},
  \ {'word': 'trentre-deux', 'menu': 32},
  \ 'unité'
  \ ]
inoremap <silent> <buffer> µ <c-o>:call lh#icomplete#new_on('\w', entries, 'lh#common#warning_msg("nominal: ".v:val)')<cr><c-x><c-O><c-p><down>

Bạn sẽ có thể quan sát (một cách gián tiếp) kết quả được áp dụng cho lựa chọn đoạn trích C ++ cho plugin mở rộng mẫu của tôi trên screencast này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.