Alternando buffers .c / .h

8

Normalmente trabalho com 2 janelas, divididas verticalmente.

O problema que eu gostaria de resolver é: saltando facilmente do cabeçalho <-> arquivo de implementação

Estou investigando, sem sorte, duas maneiras de fazer isso:

  1. Abrir arquivo alternativo na janela atual : Existem muitas maneiras de fazer isso, no entanto, não consigo encontrar uma maneira que lembre onde eu estava no arquivo anterior (por exemplo, pule para o cabeçalho, pule para trás, mas não para o mesmo lugar em que estava. )
  2. Abra um arquivo alternativo na outra janela : Isso está bem definido, já que eu só trabalho com 2 janelas, no entanto, não tenho o conhecimento do vim para fazer isso.
zach
fonte
11
Para obter uma dica da 1ª edição, consulte o final de :h line()(solução genérica): "Este comando automático salta para a última posição conhecida em um arquivo logo após abri-lo, se a marca '" estiver definida:: au BufReadPost * if line ("' \ "")> 1 && linha ("'\" ") <= linha (" $ ") | exe "normal! g` \" "| endif
VanLaser 15/02/16
Você não pode usar uma lista de atalhos e / ou marcas de arquivos cruzados?
Fruglemonkey 15/02/16
2
talvez você esteja procurando por A.vim
Christian Brabandt

Respostas:

5

Há três etapas principais para realizar o que você está perguntando:

  • obtendo o nome do arquivo alternativo
  • abrir esse arquivo na janela atual ou em outra janela, conforme desejado
  • restaurando a posição do cursor dentro desse arquivo

Para encontrar o nome do arquivo alternativo, você deseja dividir o nome do arquivo atual em "raiz" e "extensão". Uma maneira simples de fazer isso é:

let parts = split(expand("%:p"), "[.]");
let root = parts[0]
let extension = parts[1]

Se você souber que apenas alterna entre arquivos .he .cpp, poderá alterar a extensão de um para outro facilmente:

if extension == "h"
  let extension = "cpp"
else
  let extension = "h"
endif

Como alternativa, crie um dicionário que mapeie extensões conhecidas para extensões alternativas potencialmente válidas. Ou use globpath()para obter todas as alternativas possíveis para o arquivo atual:

let alternates = globpath(expand("%:h"), root . ".*")

e escolha o primeiro, ou o que for. Eu prefiro a globpathabordagem, com algumas esperanças extras que descreverei mais adiante. Depois de escolher a extensão de destino, forme o caminho de destino completo:

let target = root . "." . alternates[whicheverAlternateExtensionYouWant]

Agora você pode abrir o arquivo alternativo na janela atual:

execute "edit " . target

Ou use winnr()para obter o número da "outra janela" ( winnr("#")é a janela para a qual <C-W>psaltaria, ou você pode codificá-lo se souber que sempre será o mesmo para a sua instalação) e faça algo como:

let window = winnr("#")
execute window . "wincmd w"
execute "edit " . target

Isso fornece uma solução realmente básica para abrir arquivos alternativos. Existem algumas deficiências com a abordagem acima, desde que eu a escrevi para ser direta e é um pouco improvisada. Eu escrevi um plug - in que alterna a troca de arquivos "do jeito que eu queria" (percorrendo todos os globpath()resultados disponíveis ). Ele resolve alguns dos problemas com a simplicidade do exposto acima. Você pode verificar sua implementação se estiver interessado em explorar mais.

Finalmente, o ponto "restaurar posição do cursor". Guardei-o por último, uma vez que é ortogonal à coisa de troca alternativa (meu plug-in não lida com isso, por exemplo), mas você pode colocá-lo em sua função se quiser criar o seu próprio. :help line()possui um comando automático útil para restaurar a posição do cursor para onde estava quando o arquivo foi aberto pela última vez:

:au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g`\"" | endif

Acabei de colocar isso, ou algo muito semelhante, no meu, .vimrcjá que prefiro o comportamento o tempo todo. Você poderia facilmente colocar o código em outro lugar.


fonte
2

Você pode usar o plug - in vim-fswitch junto com a seguinte configuração no seu .vimrcarquivo:

au! BufEnter *.cpp,*.cc,*.c let b:fswitchdst = 'h,hpp'    | let b:fswitchlocs = 'reg:/src/include/,../include,./'
au! BufEnter *.h,*.hpp      let b:fswitchdst = 'cpp,cc,c' | let b:fswitchlocs = 'reg:/include/src/,../src,./'

nmap <silent> <Leader>s :FSHere<cr>

Se você digitar <Leader>(que é \, por padrão), seguido de sum .hppou .harquivo, o plugin irá verificar se uma correspondência .cpp, .ccou .cexiste arquivo:

  • substituindo includepor srcno caminho do arquivo atual
  • procurando na srcpasta acima do arquivo atual
  • procurando na pasta do arquivo atual

Há mais opções que você poderia usar para ajustar melhor seu projeto na documentação . Você levará alguns minutos, mas depois de acertar, você deve amá-lo. Eu, pessoalmente, acho muito flexível e extensível, além de funcionar tão bem para muitos tipos de arquivos (.m, .h, .inl etc ...).

XPac27
fonte
1

Na tua .vimrc

" =====[ Remap to change windows quickly ]=============================
:nnoremap <silent> <C-H> :wincmd h<CR>
:nnoremap <silent> <C-J> :wincmd j<CR>
:nnoremap <silent> <C-K> :wincmd k<CR>
:nnoremap <silent> <C-L> :wincmd l<CR>

Isso permite que você alterne rapidamente entre janelas, simplesmente usando as teclas de direção Ctrl e VIM na linha inicial. A grandeza disso é que você tem uma maneira comum de pular para qualquer janela, incluindo a janela do quickfix.

Para alternar rapidamente entre o cabeçalho e a fonte que eu uso, vim-scripts/a.vimencontrada aqui: https://github.com/vim-scripts/a.vim , use o :Acomando para alternar.

Nota lateral => Se você usa o tmux, pode usar https://github.com/christoomey/vim-tmux-navigator para pular entre as janelas vim ou nvim e um terminal sem problemas.

user1135541
fonte
1

Vou compartilhar minha versão super rápida e suja ...

Configure meus mapeamentos; alt-o abre o arquivo relacionado na mesma janela, alt-shift-o abre em uma divisão ...

nnoremap <A-o> :call EditRelatedFile()<CR>
nnoremap <A-O> :call SplitRelatedFile()<CR>

Então eu tenho uma função que obtém a lista de arquivos relacionados. Eu pretendia ajustá-lo para cortar o nome do arquivo no primeiro ponto e não no último, mas ainda é um exercício para o leitor.

function! GetRelatedFileList()
    " This function may be overloaded in a site-specific vimrc.
    let l:thisPath = expand("%:p:r") . '.*'
    let l:files = glob(l:thisPath)

    return split(l:files, '[\r\n]\+')
endfunction

Às vezes, minha instalação .vimrc é especializada por cliente; alguns têm origem e incluem hierarquias de pastas separadas, outros têm juntos. Por padrão, suponho que todos estejam próximos, mas se eu precisar caçar, fornecerei uma função de substituição como esta.

" Override the basic GetRelatedFileList coming from vimrc.
function! GetRelatedFileList()
    let l:thisDir = expand("%:p:h:t")
    if (l:thisDir ==? "src") || (l:thisDir ==? "include")
        let l:thisPath = expand("%:p:h:h")
        let l:searchPaths = l:thisPath.'/include,' . l:thisPath.'/src'
        let l:thisBase = expand("%:t:r") . '.*'
        let l:files = globpath(l:searchPaths, l:thisBase)
    else
        let l:thisPath = expand("%:p:r") . '.*'
        let l:files = glob(l:thisPath)
    endif

    return split(l:files, '[\r\n]\+')
endfunction

Então, olho a lista de arquivos para encontrar o arquivo do buffer atual e vou para o próximo na lista. Geralmente não é tão simples quanto um par .cpp / .h, muitas vezes terei outras coisas que precisam ser consideradas.

function! GetNextRelatedFile()
    let l:fileList = GetRelatedFileList()

    let l:thisFile = expand("%:p")
    let l:index = index(l:fileList, l:thisFile) + 1

    if l:index >= len(l:fileList)
        let l:index = 0
    endif

    return l:fileList[l:index]
endfunction

E finalmente as duas funções que se abrem na janela atual ou fazem uma divisão ...

function! EditRelatedFile()
    let l:file = GetNextRelatedFile()
    execute "edit" l:file
endfunction

Minha versão de divisão sempre coloca os arquivos .cpp e .c em uma divisão abaixo, caso contrário, é o padrão da divisão (que no meu caso é acima).

function! SplitRelatedFile()
    let l:file = GetNextRelatedFile()
    let l:ext = fnamemodify(l:file, ":e")
    if (l:ext ==? "cpp") || (l:ext ==? "c")
        execute "below split" l:file
    else
        execute "split" l:file
    endif
endfunction
traço-tom-bang
fonte