Czy mogę użyć „gf” (lub podobnego), aby otworzyć plik i przejść do wyszukiwanego hasła?

9

Czy istnieje sposób na uzyskanie gfpolecenia vima (lub czegoś podobnego) w celu rozpoznania +{cmd}argumentu dla ścieżek plików?

Można uruchomić vima i przejść bezpośrednio do wyszukiwanego hasła, wykonując:

$ vim +/coding_effort ~/project/file

Podobnie w trybie poleceń możesz:

:e +/coding_effort ~/project/file

Często robię notatki i odnoszę się do innych plików takich jak ten:

For more info see +/coding_effort ~/project/file where there's a detailed discussion.

Chciałbym móc wybrać +/coding_effort ~/project/file, wpisać coś w stylu gfi sprawić, że vim postąpi właściwie.

Oliver Taylor
źródło
Nie sądzę, aby można to było zrobić domyślnie, ale prawdopodobnie możesz utworzyć wtyczkę, która to robi.
EvergreenTree

Odpowiedzi:

6

Nie, pierwszym problemem jest to, że niezbędna przestrzeń między poleceniem a nazwą pliku nie jest częścią isfname'opcji ' , a dodanie jej oznaczałoby, że nie można było w ogóle rozpoznać granic plików. Musisz albo użyć wizualnego wyboru (polecenia i nazwy pliku), albo wdrożyć niestandardową analizę w przypadku gfprzeciążenia polecenia.

Po drugie, wbudowana funkcja gfnie rozpoznaje +{cmd}składni, więc naprawdę nie ma sposobu na zaimplementowanie własnego niestandardowego mapowania. Jest to oczywiście możliwe (przy użyciu funkcji takich jak expand('<cfile>'), getline()itp), ale prawdopodobnie trwa kilka linijek funkcji Vimscript.

Jeśli wybierzesz inną składnię ( filename:+command), możesz zachować oryginalne gfpolecenia i zaimplementować podział w :autocmd, podobny do tego, co robi bardzo powiązana wtyczka file: linefilespec:linenumber ).

Ingo Karkat
źródło
2

Oto funkcja, która powinna replikować wbudowane gfzachowanie, a także skanuje w poszukiwaniu prac, od +których następnie przechodzi:edit

fun! GotoWithCommand()
        let l:file = expand('<cfile>')

        " Replace ~ with the home directory
        let l:file = substitute(l:file, '^\~', $HOME, '')

        " File doesn't exist; return
        if !filereadable(l:file)
                echohl ErrorMsg
                echomsg "E447: Can't find file \"" . l:file . '" in path'
                echohl None
                return 0
        endif

        " Save cursor postion
        let l:save_cursor = getpos(".")

        " Make sure we go to the previous word (B on the first character of the
        " filename goes to the previous word, B anywhere else goes to the start of
        " the filename)
        call search('\(\s\|^\)', 'b')

        " Try to find argument to be executed; these start with a `+'
        let l:commands = ''
        while 1
                " Go one WORD backwards
                normal! B

                " Not a +; stop the loop
                if getline('.')[col('.') - 1] != '+'
                        break
                endif

                let l:commands .= ' ' . expand('<cWORD>')
        endwhile

        " Restore cursor postion
        call setpos('.', l:save_cursor)

        " Now, open the new file...
        execute ':edit ' . l:commands . ' ' . l:file
endfun

nnoremap <Leader>gf :call GotoWithCommand()<CR>

Komentarze powinny bardziej szczegółowo wyjaśniać, co robi ta funkcja ... Napisałem to rano w pociągu i (oczywiście) nie testowałem tego obszernie ;-)

Martin Tournoij
źródło
1

Jedną z opcji byłoby (zakładając, że +cmd file/pathwybrano) szarpnięcie wyboru do rejestru, a następnie wstawienie tego rejestru do wiersza polecenia. Zrobiłem to z następującym mapowaniem:

vnoremap gsf "0y:e <c-r>0<cr>

Oliver Taylor
źródło
1

Ta notacja działa ( file name+ trailing :+ / pat /)

/usr/include/stdio.h:/int printf/  -- `file name` + `:` + `/ pat /`
/usr/include/stdio.h:+/int printf/
/usr/include/stdio.h: /int printf/
/usr/include/stdio.h: /#define\s/
/usr/include/stdio.h: /^#define\sSEEK/

z funkcją i mapowaniem poniżej.

nn gf :<C-u>call Gf_search()<CR>

func! Gf_search() abort
    let word = expand('<cWORD>')
    let idx = stridx(word, ':')
    if idx != -1
        let remline = strpart(getline('.'),col('.'))
        let pat = substitute(remline, '.*[:+ ]/\([^/]*\)/.*', '\1', "")
        if pat != remline
            let pat = substitute(pat, '\\', '\\\\', 'g')
            let pat = substitute(pat, ' ', '\\ ', 'g')
            let filename = expand('<cfile>')
            exec 'e +/'.pat filename
            return
        endif
    endif
    " fallback to builtin gF
    norm! gF
endfunc
qeatzy
źródło