Cambio de búferes .c / .h


8

Normalmente trabajo con 2 ventanas, divididas verticalmente.

El problema que me gustaría resolver es: saltar fácilmente desde el archivo de implementación de encabezado <->

Estoy investigando, sin suerte, 2 formas de hacer esto:

  1. Abrir archivo alternativo en la ventana actual : hay muchas maneras de hacer esto, sin embargo, no puedo encontrar una forma de recordar dónde estaba en el archivo anterior (es decir, saltar al encabezado, saltar hacia atrás, pero no al mismo lugar donde estaba) )
  2. Abra un archivo alternativo en la otra ventana : está bien definido, ya que solo trabajo con 2 ventanas, sin embargo, no tengo el conocimiento vim para hacerlo.

1
Para una pista sobre el primer problema, vea el final de :h line()(solución genérica): "Este comando automático salta a la última posición conocida en un archivo justo después de abrirlo, si la marca '" está establecida:: au BufReadPost * if line ("' \ "")> 1 && line ("'\" ") <= line (" $ ") | exe "normal! g` \" "| endif
VanLaser

¿No puedes usar una lista de salto y / o marcas de archivos cruzados?
fruglemonkey


2
quizás estás buscando a A.vim
Christian Brabandt

Respuestas:


5

Hay tres pasos principales para lograr lo que estás pidiendo:

  • obtener el nombre del archivo alternativo
  • abrir ese archivo en la ventana actual o en otra ventana como desee
  • restaurar la posición del cursor dentro de ese archivo

Para encontrar el nombre de archivo alternativo, desea dividir el nombre del archivo actual en la "raíz" y la "extensión". Una forma simple de hacer esto es:

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

Si sabe que sólo ha vuelto a la interfaz entre .hy .cpparchivos, puede cambiar la extensión de una a otra con facilidad:

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

Alternativamente, cree un diccionario que asigne extensiones conocidas a extensiones alternativas potencialmente válidas. O use globpath()para obtener todas las alternativas posibles para el archivo actual:

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

y elige el primero, o lo que sea. Prefiero el globpathenfoque, con algunos conocimientos adicionales que describiré más adelante. Una vez que haya elegido la extensión de destino, forme la ruta de destino completa:

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

Ahora puede abrir el archivo alternativo en la ventana actual:

execute "edit " . target

O use winnr()para obtener el número de "otra ventana" ( winnr("#")es la ventana a la que <C-W>psaltaría, o puede codificarlo si sabe que siempre será el mismo para su configuración) y hacer algo como:

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

Esto le brinda una solución realmente básica para abrir archivos alternativos. Hay algunas deficiencias con el enfoque anterior, ya que lo escribí para ser sencillo y está un poco fuera de lugar. He escrito un complemento que alterna el cambio de archivos "de la manera que quería" (recorriendo todos los globpath()resultados disponibles ). Aborda algunos de los problemas con la simplicidad de lo anterior, puede consultar su implementación si está interesado en explorar más.

Finalmente, el punto "restaurar la posición del cursor". Lo guardé para el final ya que es ortogonal a la cosa de cambio alternativo (mi plugin no lo maneja, por ejemplo), pero podría ponerlo en su función si va a rodar el suyo. :help line()tiene un comando automático que es útil para restaurar la posición del cursor donde estaba cuando se abrió el archivo por última vez:

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

Acabo de poner eso, o algo muy similar, en mi .vimrcpuesto que prefiero el comportamiento todo el tiempo. Sin embargo, podría simplemente poner el código en otro lugar.


2

Puede usar el complemento vim-fswitch junto con la siguiente configuración en su .vimrcarchivo:

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>

Si escribe <Leader>(que es \por defecto), seguido de suna .hppo .harchivo, el plugin comprobar si una coincidencia .cpp, .cco .cel archivo existe:

  • reemplazando includepor srcen la ruta del archivo actual
  • mirando en la srccarpeta sobre el archivo actual
  • mirando en la carpeta del archivo actual

Hay más opciones que podría usar para ajustar mejor su proyecto en la documentación . Te llevará unos minutos, pero una vez que lo hagas bien, deberías amarlo. Personalmente, lo encuentro muy flexible y extensible, además funciona igual de bien para muchos tipos de archivos (.m, .h, .inl, etc.).


1

En tus .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>

Esto le permite moverse rápidamente entre ventanas, simplemente usando las teclas de dirección Ctrl y VIM desde la fila de inicio. Lo sorprendente de esto es que tiene una forma común de saltar a cualquier ventana, incluida la ventana de corrección rápida.

Para cambiar rápidamente entre el encabezado y la fuente que uso, se vim-scripts/a.vimencuentra aquí: https://github.com/vim-scripts/a.vim , use el :Acomando para alternar.

Nota al margen => Si usa tmux, puede usar https://github.com/christoomey/vim-tmux-navigator para saltar entre las ventanas vim o nvim y un terminal sin problemas.


1

Solo compartiré mi versión súper rápida y sucia ...

Configurar mis asignaciones; alt-o abre el archivo relacionado en la misma ventana, alt-shift-o se abre en una división ...

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

Luego tengo una función que obtiene la lista de archivos relacionados. He tenido la intención de ajustarlo para cortar el nombre del archivo en el primer punto en lugar del último, pero eso sigue siendo un ejercicio para el lector.

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

Mi configuración .vimrc a veces se especializa por cliente; algunos tienen fuente e incluyen jerarquías de carpetas separadas, algunos los tienen juntos. Por defecto, supongo que están todos cerca, pero si necesito cazar, proporcionaré una función de reemplazo 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

Luego miro a través de esa lista de archivos para encontrar el archivo del búfer actual y pasar al siguiente de la lista. No suele ser tan simple como un par .cpp / .h, a menudo tendré que considerar otras cosas.

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

Y finalmente, las dos funciones que se abren en la ventana actual o se dividen ...

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

Mi versión de división siempre coloca los archivos .cpp y .c en una división por debajo, de lo contrario, se divide por defecto (que en mi caso está arriba).

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.