Переключение буфера .c / .h


8

Я обычно работаю с 2 окнами, вертикально разделенными.

Проблема, которую я хотел бы решить, заключается в следующем: легко переходить назад и вперед из файла реализации заголовка <->

Я исследую, без удачи, 2 способа сделать это:

  1. Открыть альтернативный файл в текущем окне : Есть много способов сделать это, однако я не могу найти способ, который бы помнил, где я был в предыдущем файле (то есть перейти к заголовку, перейти назад, но не туда, где я был ).
  2. Откройте альтернативный файл в другом окне : это четко определено, так как я когда-либо работаю только с двумя окнами, однако мне не хватает знания vim для этого.

1
Подсказка к 1-й проблеме приведена в конце :h line()(универсальное решение): «Эта автокоманда переходит на последнюю известную позицию в файле сразу после его открытия, если установлена ​​метка« »: au BufReadPost * if line (») \ "")> 1 && line ("'\" ") <= line (" $ ") | exe "normal! g` \" "| endif
VanLaser

Разве вы не можете использовать список переходов и / или метки между файлами?
fruglemonkey


2
возможно, вы ищете A.vim
Кристиан Брабандт

Ответы:


5

Есть три основных шага в выполнении того, что вы просите:

  • получение альтернативного имени файла
  • открывая этот файл в текущем окне или в другом окне по желанию
  • восстановление позиции курсора в этом файле

Чтобы найти альтернативное имя файла, вы хотите разбить текущее имя файла на «корень» и «расширение». Простой способ сделать это:

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

Если вы знаете, что переключаетесь только между файлами .hи .cppфайлами, вы можете легко изменить расширение с одного на другое:

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

Или создайте словарь, сопоставляющий известные расширения с потенциально допустимыми альтернативными расширениями. Или используйте, globpath()чтобы получить все возможные альтернативы для текущего файла:

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

и выберите первый или что-то еще. Я предпочитаю globpathподход, с некоторыми дополнительными умами, которые я опишу позже. Как только вы выбрали целевое расширение, сформируйте полный целевой путь:

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

Теперь вы можете открыть альтернативный файл в текущем окне:

execute "edit " . target

Или используйте, winnr()чтобы получить номер «другого окна» ( winnr("#")это окно, к <C-W>pкоторому нужно перейти, или вы можете жестко закодировать его, если вы знаете, что оно всегда будет одинаковым для ваших настроек) и сделать что-то вроде:

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

Это дает вам действительно простое решение для открытия альтернативных файлов. Есть несколько недостатков с вышеупомянутым подходом, так как я написал это, чтобы быть простым, и это немного не в манере. Я написал плагин, который выполняет альтернативное переключение файлов "так, как я хотел" (циклически просматривая все доступные globpath()результаты). Он решает некоторые проблемы с простотой вышеперечисленного, вы можете проверить его реализацию, если вы заинтересованы в изучении большего.

Наконец, точка «восстановить позицию курсора». Я сохранил его напоследок, так как он ортогонален альтернативному переключению (мой плагин, к примеру, не обрабатывает его), но вы можете использовать его в своей функции, если вы собираетесь выполнить свою собственную. :help line()имеет автокоманду, которая полезна для восстановления позиции курсора туда, где она была, когда файл последний раз открывался:

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

Я просто включил это, или что-то очень похожее, в мое, .vimrcтак как я все время предпочитаю поведение. Вы можете легко разместить код в другом месте.


2

Вы можете использовать плагин vim-fswitch вместе со следующей конфигурацией в вашем .vimrcфайле:

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>

Если тип <Leader>(который \по умолчанию) , а затем sв .hppили .hфайл, плагин будет проверять , если соответствующий .cpp, .ccили .cфайл существует:

  • путем замены includeна srcв пути текущего файла
  • посмотрев в srcпапке над текущим файлом
  • просматривая папку текущего файла

Есть больше опций, которые вы можете использовать, чтобы лучше соответствовать вашему проекту в документации . Это займет у вас несколько минут, но как только вы все поймете правильно, вам это понравится. Лично я считаю его очень гибким и расширяемым, плюс он работает так же хорошо для многих типов файлов (.m, .h, .inl и т. Д.).


1

В вашей .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>

Это позволяет быстро перемещаться между окнами, просто используя клавиши управления Ctrl и VIM из домашней строки. Удивительно то, что у вас есть один общий способ перейти к любому окну, включая окно быстрого исправления.

Чтобы быстро переключаться между заголовком и источником, я использую vim-scripts/a.vimздесь: https://github.com/vim-scripts/a.vim , используйте :Aкоманду для переключения.

Примечание:> Если вы используете tmux, вы можете использовать https://github.com/christoomey/vim-tmux-navigator для быстрого перехода между окнами vim или nvim и терминалом.


1

Я просто поделюсь своей супер быстрой и грязной версией ...

Настройте мои отображения; alt-o открывает связанный файл в том же окне, alt-shift-o открывается в режиме разделения ...

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

Тогда у меня есть функция, которая получает список связанных файлов. Я намеревался настроить его, чтобы разделить имя файла по первой точке, а не по последней, но это все еще упражнение для читателя.

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

Моя установка .vimrc иногда специализируется для каждого клиента; некоторые имеют источник и включают в отдельные иерархии папок, некоторые имеют их вместе. По умолчанию я предполагаю, что они все рядом, но если мне понадобится охота, я предоставлю функцию замены, подобную этой.

" 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

Затем я просматриваю этот список файлов, чтобы найти файл текущего буфера и перейти к следующему в списке. Это не так просто, как пары .cpp / .h, часто у меня есть другие вещи, которые необходимо учитывать.

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

И, наконец, две функции, которые либо открываются в текущем окне, либо делят ...

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

Моя разделенная версия всегда помещает файлы .cpp и .c в разделение ниже, в противном случае разделение по умолчанию (что в моем случае выше).

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.