ความสมบูรณ์แบบไดนามิก


12

ฉันพยายามปรับปรุงฟังก์ชั่นการเติมเต็มให้สมบูรณ์ ฉันต้องการอัปเดตตัวเลือกที่ปรากฏในเมนูป๊อปอัปขณะที่พิมพ์อักขระใหม่

ฟังก์ชั่นความสมบูรณ์ของฉันคือ

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

ที่ฉันใช้กับ

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

จากความเข้าใจในเอกสารของฉันความจริงที่ฉันใช้<c-p>ฉันเข้าสู่สถานะที่สาม (ตาม | ins-complete-menu |) และเมื่อฉันพิมพ์"อักขระที่พิมพ์ได้และไม่ใช่สีขาว"ฉันควรจะสามารถ"เพิ่ม ตัวละครนี้และลดจำนวนการแข่งขัน "

เมื่อฉันพิมพ์ในโหมดแทรกเมนูเสร็จจะปรากฏขึ้นตามที่คาดไว้ อนิจจาเมื่อฉันพิมพ์x(หลังµ) ฉันออกจากโหมดเสร็จสิ้นและuxเป็นสิ่งที่ฉันได้รับในบัฟเฟอร์ของฉัน

ฉันทำอะไรผิดหรือพลาดไปในเอกสารประกอบ?

หมายเหตุ: ฉันเห็นว่าไม่มีrefresh=alwaysผลลัพธ์จะถูกกรองยกเว้นฉันต้องการเรียกใช้ฟังก์ชันอีกครั้งเพื่อใช้ตัวกรองที่กำหนดเอง

(ในกรณีที่ฉันใช้ gvim 7.4-908)


ดูเหมือนว่าจะเป็นข้อผิดพลาด มันไม่ได้ผลสำหรับฉันเช่นกัน (ฉันใช้ Vim 7.4.944)
Karl Yngve Lervåg

มันควรจะทำงานอย่างไร นั่นคือสิ่งที่ฉันไม่รู้
Luc Hermitte

เอกสารดูเหมือนจะบ่งบอกว่ามันควรจะทำงาน
Karl Yngve Lervåg

คำตอบ:


3

หลังจากการตรวจสอบเพิ่มเติม (และวิศวกรรมย้อนกลับ)

ฉันไม่สามารถอธิบายได้ว่าเหตุใดความสมบูรณ์จึงไม่ปฏิบัติตามเอกสารอย่างเคร่งครัด ฉันจะต้องถาม vim_dev ฉันเดา

อย่างไรก็ตามดูเหมือนว่าวิธีการที่จะประกอบด้วยในการลงทะเบียนฟังCursorMovedIที่จะทริกเกอร์เสร็จอีกครั้งทุกครั้งที่มีการแทรกตัวละคร

ความยากลำบากคือการรู้ว่าเมื่อใดที่จะหยุด

  • CompletionDone ไม่มีประโยชน์เนื่องจากมันจะถูกเรียกใช้หลังจากกดปุ่มทุกครั้ง
  • InsertLeave เป็นการเริ่มต้นที่ดี แต่ไม่ครอบคลุมทุกกรณีเช่น
    • เมื่อตัวละครที่ไม่มีการจับคู่ถูกพิมพ์อีกเราต้องหยุด
    • เมื่อผู้ใช้เลือกหนึ่งรายการเมนูเราจะต้องหยุดเช่นกัน
      ฉันไม่พบวิธีอื่นนอกจากการเอาชนะ<cr>และ<c-y>.

ปัญหาอื่น ๆ รวมถึงการตรวจจับเมื่อไม่มีสิ่งใดเปลี่ยนแปลงเพื่อหลีกเลี่ยงการวนซ้ำไม่สิ้นสุดเป็นต้น

ไม่ว่าด้วยวิธีใดนี่คือรหัสปัจจุบันของฉัน (ซึ่งจะใช้ในปลั๊กอินอื่น ๆ ) รุ่นล่าสุดจะถูกเก็บรักษาไว้ที่นี่ มันค่อนข้างยาว แต่ที่นี่มันคือ:

" ## 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

ซึ่งสามารถใช้กับ:

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>

คุณควรจะสามารถสังเกต (ทางอ้อม) ผลลัพธ์ที่นำไปใช้กับการเลือกตัวอย่าง C ++ สำหรับปลั๊กอินตัวขยายเทมเพลตของฉันในscreencastนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.