Posso usar "gf" (ou similar) para abrir um arquivo e pular para um termo de pesquisa?

9

Existe uma maneira de obter o gfcomando do vim (ou algo semelhante) para reconhecer um +{cmd}argumento para caminhos de arquivos?

Pode-se iniciar o vim e ir diretamente para um termo de pesquisa, fazendo:

$ vim +/coding_effort ~/project/file

Da mesma forma, no modo de comando, você pode fazer:

:e +/coding_effort ~/project/file

Costumo fazer anotações e me refiro a outros arquivos como este:

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

Eu adoraria poder selecionar +/coding_effort ~/project/file, digitar algo como gfe fazer com que o vim faça a coisa certa.

Oliver Taylor
fonte
Eu não acho que exista alguma maneira de fazer isso por padrão, mas você provavelmente poderia criar um plugin que o faça.
EvergreenTree

Respostas:

6

Não, o primeiro problema é que o espaço necessário entre o comando e o nome do arquivo não faz parte da isfname'opção ' e adicioná-lo significaria que as bordas do arquivo não poderiam ser reconhecidas. Você sempre deve usar uma seleção visual (de comando e nome de arquivo) ou implementar a análise personalizada em uma gfsobrecarga de comando.

Em segundo lugar, o built-in gfnão reconhece a +{cmd}sintaxe, então não há realmente nenhuma maneira de implementar seu próprio mapeamento personalizado. Isso certamente é possível (usando funções como expand('<cfile>'), getline()etc.), mas provavelmente requer algumas linhas da função Vimscript.

Se você escolher uma sintaxe diferente ( filename:+command), poderá manter os gfcomandos originais e implementar a divisão em um :autocmd, semelhante ao que o arquivo muito relacionado : o plugin de linha faz para filespec:linenumber).

Ingo Karkat
fonte
2

Aqui está uma função que deve replicar o gfcomportamento interno e também procura por trabalhos que começam com os +quais são passados ​​para: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>

Os comentários devem explicar o que a função faz com mais detalhes ... Escrevi isso no trem pela manhã e (obviamente) não o testei extensivamente ;-)

Martin Tournoij
fonte
1

Uma opção seria (assumindo que +cmd file/pathestá selecionada) para puxar a seleção para um registro e, em seguida, insira esse registro no prompt de comando. Eu fiz isso com o seguinte mapeamento:

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

Oliver Taylor
fonte
1

Esta notação funciona ( 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/

com função e mapeamento abaixo.

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
fonte