จะสร้างฟังก์ชั่นเติมข้อความอัตโนมัติของตัวเองได้อย่างไร?


22

ฉันจะสร้างรายการการทำให้สมบูรณ์อัตโนมัติของตัวเองสำหรับไฟล์บางประเภทได้อย่างไร

ยกตัวอย่างเช่นผมอยาก CSS และ HTML เพื่อเติมข้อความอัตโนมัติจากรายการคลาส CSS ในFontAwesome

คำตอบ:


22

ความสมบูรณ์ของพจนานุกรมจะเป็นวิธีแก้ปัญหาราคาถูกและไม่ล่วงล้ำ:

  1. บันทึกfontawesome.txt ที่ใดที่หนึ่งบนเครื่องของคุณ

  2. ใส่สิ่งนี้ในafter/ftplugin/css.vim(สร้างไฟล์หากไม่มี):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. เริ่มเซสชันใหม่หรือทำ:eในบัฟเฟอร์ CSS เพื่อบีบอัดไฟล์ด้านบน

  4. กด<C-n>หรือ<C-p>ในโหมดแทรก

  5. สนุก!

    พจนานุกรมสมบูรณ์

อ้างอิง:

:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'

17

แก้ไขขอบคุณความคิดเห็นของ romainl ฉันได้แก้ไขคำตอบของฉันเพื่อแสดงวิธีการสร้างฟังก์ชั่นความสมบูรณ์ที่ผู้ใช้กำหนด ในรุ่นก่อนหน้าฉันกำลังเอาชนะ buil-in omni-completion ซึ่งไม่ดีเพราะผู้ใช้จะหลวมความสมบูรณ์เริ่มต้นซึ่งมีประสิทธิภาพมาก


โซลูชัน vimscript

ทางออกหนึ่งคือการใช้ vimscript และความจริงที่ว่า vim ให้คุณสร้างฟังก์ชั่นการเติมเต็มแบบกำหนดเอง

ข้อดีของการแก้ปัญหานี้คือคุณไม่ต้องใช้ปลั๊กอินเพิ่มเติมคุณสามารถสร้างฟังก์ชั่นความสมบูรณ์ที่ผู้ใช้กำหนดและใช้คุณสมบัติความสมบูรณ์แบบในตัว

ฉันจะใช้ตัวอย่างของคลาส fontAwesome ในcssไฟล์:

สร้างไฟล์~/.vim/autoload/csscomplete.vimและวางบรรทัดต่อไปนี้ลงไป:

let s:matches=".fa-lg .fa-2x .fa-3x .fa-4x .fa-5x .fa-fw .fa-ul .fa-ul .fa-li .fa-li.fa-lg .fa-border .fa-pull-left .fa-pull-right .fa.fa-pull-left"

function! csscomplete#CompleteFA(findstart, base)
    if a:findstart
        " locate the start of the word
        let line = getline('.')
        let start = col('.') - 1
        while start > 0 && (line[start - 1] =~ '\a' || line[start - 1] =~ '.' || line[start - 1] =~ '-')
            let start -= 1
        endwhile
        return start
    else
        " find classes matching "a:base"
        let res = []
        for m in split(s:matches)
            if m =~ '^' . a:base
                call add(res, m)
            endif
        endfor
        return res
    endif
endfun

จากนั้นสร้างไฟล์~/.vim/after/ftplugin/css.vimและวางไว้ในบรรทัดต่อไปนี้:

setlocal completefunc=csscomplete#CompleteFA

<C-x><C-u>จากนั้นคุณสามารถเรียกฟังก์ชั่นเสร็จสิ้นการที่ผู้ใช้กำหนดของคุณด้วย มันจะพยายามหาคำที่ตรงกับคำที่พิมพ์ล่าสุด

ในภาพหน้าจอฉันพิมพ์.fa-lแล้วเรียกใช้ฟังก์ชันด้วย<C-x><C-u>:

ป้อนคำอธิบายรูปภาพที่นี่


มันทำงานยังไง?

ก่อนอื่นนี่คือหัวข้อเอกสารที่เกี่ยวข้อง:

หากคุณต้องการที่จะสร้างเสร็จที่กำหนดเองสำหรับ filetype $HOME/.vim/autoload/{FILETYPE}complete.vimโดยเฉพาะอย่างยิ่งที่คุณต้องใส่ไว้ในไฟล์

จากนั้นในไฟล์นี้คุณต้องสร้างฟังก์ชั่นความสมบูรณ์ซึ่งเรียกว่าสองครั้ง

  • ในการโทรครั้งแรกอาร์กิวเมนต์แรกคือตำแหน่งปัจจุบันของเคอร์เซอร์และฟังก์ชั่นจะกำหนดคำให้เสร็จสมบูรณ์ ในฟังก์ชั่นของฉันฉันใช้การเปรียบเทียบ 3 แบบเพื่อทำให้คำศัพท์เสร็จสมบูรณ์เพราะชั้นเรียนสามารถประกอบด้วยตัวอักษร.และ- (ฉันคิดว่ามันเป็นไปได้ที่จะปรับปรุงการจับคู่นี้ แต่ฉันแย่มากกับ regex)

  • บนสายที่สองอาร์กิวเมนต์ที่สองคือคำให้ตรงแล้วฟังก์ชั่นเปรียบเทียบกับรายการของคลาสที่เป็นไปได้เพื่อให้ตรงกับ1 ที่นี่คุณจะเห็นว่าฉันกลับพจนานุกรมซึ่งจะเติมเมนูเสร็จสมบูรณ์แต่เมื่อคุณอ่านเอกสารคุณจะเห็นว่าคุณสามารถสร้างพจนานุกรมที่ซับซ้อนมากขึ้นเพื่อปรับแต่งการทำงานของฟังก์ชันของคุณ

คุณต้องบอกให้ Vim "สำหรับไฟล์ประเภทนี้ใช้ฟังก์ชั่นที่สมบูรณ์ที่ฉันสร้างขึ้นนี้" ต้องการทำเช่นนั้นคุณจะต้องตั้งcompletefuncชื่อฟังก์ชั่นที่คุณสร้างขึ้น (ที่นี่csscomplete#CompleteFA) $HOME/.vim/after/ftplugin/{FILETYPE}.vimและการตั้งค่านี้จะต้องทำในแฟ้ม

1ในฟังก์ชั่นของฉันตัวแปรs:matchesมีการแข่งขันที่เป็นไปได้ทั้งหมด ที่นี่ฉันใส่คำแนะนำสำหรับการอ่านเท่านั้น แต่คุณสามารถใส่คลาสทั้งหมดที่เสนอโดย FontAwesome (คุณสามารถค้นหารายการทั้งหมดในไฟล์นี้สร้างโดย romainl)


ถ้าฉันไม่ชอบ Vimscript ล่ะ?

ความเป็นไปได้อย่างหนึ่งคือการใช้ปลั๊กอินYoucompleteMeซึ่งให้บริการ API เพื่อเล่นกับเมนูเสร็จ คุณสามารถสร้างฟังก์ชั่นหลามซึ่งจะทำงานจับคู่และจะใช้ API เพื่อเติมอินเทอร์เฟซ Vim รายละเอียดเพิ่มเติมที่นี่


2
การทำ omni ที่เป็นค่าเริ่มต้นสำหรับ CSS และ HTML นั้นค่อนข้างมีประโยชน์อยู่แล้วและคุณสามารถมีได้ครั้งละหนึ่งอันเท่านั้นดังนั้นฉันขอแนะนำให้ใช้ :help i_ctrl-x_ctrl-uดู
romainl

@romject: ถูกต้องแน่นอนฉันจะดูวิธีปรับคำตอบของฉัน
Statox

5

บางครั้งคุณต้องการให้การเติมข้อมูลอัตโนมัติที่กำหนดเองนั้นไม่รบกวนการเติมข้อความอัตโนมัติในตัวหรือที่ผู้ใช้กำหนดเอง สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับสคริปต์หรือปลั๊กอินที่ต้องการใช้งานกับไฟล์ประเภทต่างๆ

สามารถทำได้ค่อนข้างง่ายด้วย complete() ฟังก์ชั่นและเสื้อคลุมเรียบง่าย ขั้นตอนส่วนใหญ่เหมือนกับที่อธิบายไว้ใน :help complete-functions และคำตอบของ Statox ยกเว้นว่าคุณจำเป็นต้องกำหนดการแมปของคุณเองและต้องโทรหาcomplete()ตัวเองแทนการส่งคืนค่า

นี่เป็นตัวอย่างพื้นฐานความคิดเห็นควรอธิบายวิธีการทำงาน

" Map <C-x><C-m> for our custom completion
inoremap <C-x><C-m> <C-r>=MyComplete()<CR>

" Make subsequent <C-m> presses after <C-x><C-m> go to the next entry (just like
" other <C-x>* mappings)
inoremap <expr> <C-m> pumvisible() ?  "\<C-n>" : "\<C-m>"

" Complete function for addresses; we match the name & address
fun! MyComplete()
    " The data. In this example it's static, but you could read it from a file,
    " get it from a command, etc.
    let l:data = [
        \ ["Elmo the Elk", "daring@brave.com"],
        \ ["Eek the Cat", "doesnthurt@help.com"]
    \ ]

    " Locate the start of the word and store the text we want to match in l:base
    let l:line = getline('.')
    let l:start = col('.') - 1
    while l:start > 0 && l:line[l:start - 1] =~ '\a'
        let l:start -= 1
    endwhile
    let l:base = l:line[l:start : col('.')-1]

    " Record what matches − we pass this to complete() later
    let l:res = []

    " Find matches
    for m in l:data
        " Check if it matches what we're trying to complete; in this case we
        " want to match against the start of both the first and second list
        " entries (i.e. the name and email address)
        if l:m[0] !~? '^' . l:base && l:m[1] !~? '^' . l:base
            " Doesn't match
            continue
        endif

        " It matches! See :help complete() for the full docs on the key names
        " for this dict.
        call add(l:res, {
            \ 'icase': 1,
            \ 'word': l:m[0] . ' <' . l:m[1] . '>, ',
            \ 'abbr': l:m[0],
            \ 'menu': l:m[1],
            \ 'info': len(l:m) > 2 ? join(l:m[2:], "\n") : '',
        \ })
    endfor

    " Now call the complete() function
    call complete(l:start + 1, l:res)
    return ''
endfun
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.