내 자동 완성 기능을 만드는 방법은 무엇입니까?


22

특정 파일 형식에 대한 자체 자동 완성 목록을 작성하려면 어떻게합니까?

예를 들어 FontAwesome 의 CSS 클래스 목록에서 css 및 html을 자동 완성하고 싶습니다 .

답변:


22

사전 완성은 저렴하고 방해가되지 않는 솔루션입니다.

  1. 컴퓨터 어딘가에 fontawesome.txt를 저장 하십시오.

  2. 이것을 넣으 after/ftplugin/css.vim십시오 (파일이 존재하지 않으면 파일을 만드십시오).

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. 새 세션을 시작하거나 :eCSS 버퍼에서 위의 파일을 강제로 소싱하십시오.

  4. 를 눌러 <C-n>또는 <C-p>삽입 모드에서,

  5. 즐겨!

    사전 완성

참고:

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

17

편집 romainl의 의견 덕분에 사용자 정의 완료 함수를 만드는 방법을 보여주기 위해 답변을 편집했습니다. 이전 버전에서는 사용자가 기본 완성 기능을 느슨하게 만들었 기 때문에 좋지 않은 내장 완료 옴니 완성을 재정의했습니다.


vimscript 솔루션

한 가지 해결책은 vimscript와 vim을 사용하여 사용자 정의 완료 함수를 작성하는 것입니다.

이 솔루션의 장점은 추가 플러그인이 필요하지 않기 때문에 사용자 정의 완료 기능을 만들고 내장 완료 기능을 사용할 수 있다는 것입니다.

css파일 에서 fontAwesome 클래스의 예를 사용하겠습니다 .

파일을 작성하고 ~/.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>.

여기에 이미지 설명을 입력하십시오


어떻게 작동합니까?

먼저 여기에 몇 가지 관련 문서 주제가 있습니다.

특정 파일 유형에 대해 사용자 정의 완료를 작성하려면 파일에 입력해야합니다 $HOME/.vim/autoload/{FILETYPE}complete.vim.

그런 다음이 파일에서 완료 함수를 두 번 작성해야합니다.

  • 첫 번째 호출에서 첫 번째 인수는 커서의 현재 위치이며 함수는 완료 할 단어를 결정합니다. 내 기능에서 나는 클래스가 문자로 구성 할 수 있기 때문에 전체에 단어를 얻기 위해 3 개 비교를 사용 .하고 - (나는이 매칭을 향상시킬 수있다 생각하지만 난 정규식 정말 나쁜거야)

  • 두 번째 호출에서 두 번째 인수는 일치시킬 단어이고 함수는이를 일치하는 가능한 클래스 목록과 비교하여 1 과 일치 합니다. 여기서 완성 메뉴를 채울 사전을 반환 하지만 설명서를 읽으면 훨씬 더 복잡한 사전을 만들어 함수의 동작을 더 많이 사용자 지정할 수 있음을 알 수 있습니다.

또한 Vim에 "이런 종류의 파일에는 내가 만든이 완전한 기능을 사용하십시오"라고 알려야합니다. 그렇게하려면 completefunc생성 한 기능의 이름 (여기 csscomplete#CompleteFA)으로 설정해야하며이 설정은 파일에서 수행해야합니다 $HOME/.vim/after/ftplugin/{FILETYPE}.vim.

1 내 함수에서 변수 s:matches는 가능한 모든 일치 항목을 포함합니다. 여기에서는 가독성에 대한 몇 가지 제안 만 제시했지만 FontAwesome에서 제공하는 모든 클래스를 넣을 수 있습니다 (romainl 작성한 이 파일 에서 전체 목록을 찾을 수 있음).


Vimscript가 마음에 들지 않으면 어떻게합니까?

한 가지 가능성은 완성 메뉴를 가지고 노는 API를 제공하는 YoucompleteMe 플러그인을 사용하는 것 입니다. 일치하는 작업을 수행하고 API를 사용하여 Vim 인터페이스를 채우는 Python 함수를 작성할 수 있습니다. 자세한 내용은 여기를 참조 하십시오 .


2
CSS와 HTML의 기본 옴니 완성은 이미 매우 유용하며 한 번에 하나씩 만 사용할 수 있으므로 대신 "사용자 정의 완성"을 사용하는 것이 좋습니다. 참조하십시오 :help i_ctrl-x_ctrl-u.
romainl

@ romainl : 당신은 절대적으로 맞습니다, 나는 내 대답을 조정하는 방법을 볼 것입니다.
statox

5

때로는 내장 또는 사용자 정의 자동 완성을 전혀 방해하지 않는 사용자 지정 자동 완성을 원할 때가 있습니다. 이 기능은 다양한 파일 형식에 사용할 수있는 스크립트 또는 플러그인에 특히 유용합니다.

이것은 complete() 함수와 간단한 래퍼로 상당히 쉽게 수행 할 수 있습니다 . :help complete-functions 자신의 매핑을 정의해야 complete()하고 값을 반환하는 대신 자신 을 호출해야한다는 점을 제외하면 대부분의 절차는 Statox의 답변과 설명 과 동일 합니다.

다음은 기본적인 예입니다. 의견은 작동 방식을 설명해야합니다.

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