Trabajo en un proyecto C ++ bastante grande. Uno de los aspectos más frustrantes de su organización son las funciones muy grandes ubicadas dentro de archivos ridículamente grandes.
A menudo quiero buscar cualquier instancia de una variable global particular o llamada de función, restringida a la función actual. ¿Existe una fórmula razonablemente simple para lograr esto?
(Tengo ctags instalados y uso Tagbar ... lo que podría ser útil para esto)
Explicación: vnoremap significa mapear el lado izquierdo ifal lado derecho [[mO][mientras está en modo visual. ifsignifica en función , aunque puede cambiar el nombre de esto si lo desea. [[salta al comienzo de la función. Ose mueve al otro extremo del texto seleccionado visualmente y luego se ][mueve al final de la función.
Entonces, si desea buscar en una función, ahora ingresa al modo visual con vy selecciona toda la función con if. Ahora salga del modo visual con <esc>y busque con /\%V. \%Vrestringe su búsqueda al texto previamente seleccionado. Si no quieres tener que golpear <esc>/\%V, también puedes agregar esto a tu .vimrc:
vnoremap / <esc>/\%V
Entonces, su secuencia de pulsaciones de teclas se vería así:
vif/foo<enter>
y esto encontrará todas las ocurrencias de foo en la función actual.
El único inconveniente de este método es que espera que las llaves de apertura y cierre tengan ambas sangría 0. Si trabaja regularmente con código que no tiene esto, p. Ej.
int foo() {
bar()
}
entonces esta versión un poco más complicada funcionará:
vnoremap if ][ma%O'a
Esto solo espera que la llave de cierre tenga 0 sangría. Si la llave de apertura tiene sangrías, aún funciona, aunque ocupa una marca. Si usa regularmente la marca 'a', puede mover esto, por ejemplo
Por desgracia, esto no funciona bien con las funciones de C ++. A diferencia de las funciones C, es probable que tengan sangría (es el caso de las funciones de miembros en línea definidas en su definición de clase y con la sangría predeterminada de las funciones dentro de los espacios de nombres). Sin embargo, su idea puede desarrollarse gracias al rango de definición de funciones que se puede obtener con ctags. Lo hago en la función lh#dev#find_function_boundariesde lh-dev
Luc Hermitte
3
Buen enfoque. Si puede encontrar de manera confiable la línea superior de la función, entonces puede moverse hacia {y luego usar %para llegar a la línea inferior. No estoy seguro de cómo puede encontrar el inicio de la función en C ++, pero esto funciona bien para Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle
1
En cuanto a tu última edición. CTRL-]salta a la etiqueta debajo del cursor. No al inicio de la función actual. No va a ayudar
Luc Hermitte
En cuanto a la nueva edición. No es tan simple. La dificultad es que vim conozca la función actual. Si tuviera la información, no necesitaría ayuda de ctags. La única forma de obtener la información (de ctags) es analizar los comandos de salto a declaración producidos por ctags. Si estos comandos fueran :linenumber, vim podría hacer lo que hago en mi complemento. Pero no hay garantía, y estos comandos pueden ser buscados /pattern: Vim no puede probar todos los patrones para saber cuál coincide con la función actual. Por otro lado, no estoy al tanto de ninguna acción de Vim para saltar al inicio de la corriente. función
Luc Hermitte
6
La solución de DJ McMayhem me inspiró a escribir la mía propia que se basa en ctags y matchit para hacer un análisis adecuado de los límites de las funciones.
La parte difícil ya ha sido realizada por lh-dev y lh-tags durante varios años:
el archivo actual se analiza a través de etiquetas con las opciones correctas
buscamos todas las definiciones de funciones en la base de datos de etiquetas que está restringida a las etiquetas obtenidas para el archivo actual
Gracias a la base de datos, tenemos los números de línea de inicio para todas las funciones (bueno, las etiquetas pueden pasar por alto templatey inlineparte)
con una búsqueda iterativa simple (podría haberse realizado una búsqueda binaria, pero bueno, se supone que los archivos son "cortos"), se encuentra el comienzo de la función actual
Y gracias al complemento matchit, su línea final también se encuentra: veo que ctags universales ofrece un endcampo que se puede usar con C, C ++, Python y Vim que también se puede usar para encontrar el final de una función.
Tenga en cuenta que cualquier parte de este algoritmo podría anularse según el tipo de archivo. es decir, la detección de límites de las funciones de Python podría buscar defy analizar la sangría, simplemente podríamos buscar functionen javascript, etc. hacer para Python)
Así que defino ahora dos nuevas asignaciones: una asignación de modo visual y una asignación de modo pendiente de operador:
onoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr>
xnoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr><esc>gv
Que se basan en:
function! lh#dev#_select_current_function() abort
let fn = lh#dev#find_function_boundaries(line('.'))
exe fn.lines[0]
normal! v
exe fn.lines[1]
endfunction
Encontrar el principio y el final de una función puede ser difícil, especialmente en un lenguaje sin una functionpalabra clave ... y muchos estilos de sangría conflictivos.
Si su función termina con una llave de cierre sola en su propia línea (como en 10 de los 13 estilos enumerados aquí ), puede seleccionarla visualmente con algo como esto:
xnoremap if /^\s*}<CR><Esc>V%
A partir de ahí, buscar foodentro de su función es solo una cuestión de:
:'<,'>g/foo/#
En conjunto, podemos obtener un mapeo bastante agradable:
xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>
Dicho esto, el mapeo del modo visual probablemente se dejaría engañar fácilmente por una whileo una, ifpor lo que probablemente se beneficiaría de un poco de pulido. Además, mantener la selección visual puede no ser una muy buena idea ...
Esto solo selecciona el siguiente bloque que puede encontrar. No funciona en absoluto una vez que añadir if, for, while, etc.
James
3
Una solución imperfecta es usar pliegues . Doblar todo:
set foldmethod=syntax
set foldlevel=0
set foldminlines=0
Dígale a Vim que no abra las áreas plegadas para los resultados de búsqueda:
set foldopen-=search
Y luego abra el pliegue en la función en cuestión ( zO).
Ahora, todos los resultados para el texto buscado en una región plegada darán lugar a que Vim salte a la línea de plegado una vez, y luego continúe con el siguiente resultado.
Por ejemplo, en el caso a continuación:
La función plegada tiene muchos usos size, pero nno me guiará por cada uso de sizeesa función.
" configure the plugin (once, vimrc):
map g/ <Plug>(operator-search)
" 1. use ctags etc. to jump to the beginning of the target function;
" 2. move cursor inside the function definition, then:
g/i{
... ahora puede insertar su término de búsqueda en el indicador dado; presione npara ver cómo los resultados de búsqueda se limitan al movimiento / objeto de texto proporcionado actualmente. Dado que este es un operador Vim (es decir, composable), si tiene una buena función de objeto de texto, ni siquiera necesita moverse dentro del cuerpo de la definición antes de buscar, sino que usa directamente algo similar g/ifo similar.
lh#dev#find_function_boundaries
de lh-dev{
y luego usar%
para llegar a la línea inferior. No estoy seguro de cómo puede encontrar el inicio de la función en C ++, pero esto funciona bien para Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
CTRL-]
salta a la etiqueta debajo del cursor. No al inicio de la función actual. No va a ayudar:linenumber
, vim podría hacer lo que hago en mi complemento. Pero no hay garantía, y estos comandos pueden ser buscados/pattern
: Vim no puede probar todos los patrones para saber cuál coincide con la función actual. Por otro lado, no estoy al tanto de ninguna acción de Vim para saltar al inicio de la corriente. funciónLa solución de DJ McMayhem me inspiró a escribir la mía propia que se basa en ctags y matchit para hacer un análisis adecuado de los límites de las funciones.
La parte difícil ya ha sido realizada por lh-dev y lh-tags durante varios años:
template
yinline
parte)end
campo que se puede usar con C, C ++, Python y Vim que también se puede usar para encontrar el final de una función.Tenga en cuenta que cualquier parte de este algoritmo podría anularse según el tipo de archivo. es decir, la detección de límites de las funciones de Python podría buscar
def
y analizar la sangría, simplemente podríamos buscarfunction
en javascript, etc. hacer para Python)Así que defino ahora dos nuevas asignaciones: una asignación de modo visual y una asignación de modo pendiente de operador:
Que se basan en:
Te perdono los cientos de líneas de código de
lh#dev#find_function_boundaries()
Y gracias al mapeo de DJ McMayhem
podemos hacer una
vif/pattern
búsquedapattern
en la función actual.También podemos eliminar funciones con
dif
, tirarlas conyif
, etc.Así es como se ve cuando se aplica en una función realista de C ++ (es decir, no tiene sangría de 0):
fuente
Encontrar el principio y el final de una función puede ser difícil, especialmente en un lenguaje sin una
function
palabra clave ... y muchos estilos de sangría conflictivos.Si su función termina con una llave de cierre sola en su propia línea (como en 10 de los 13 estilos enumerados aquí ), puede seleccionarla visualmente con algo como esto:
A partir de ahí, buscar
foo
dentro de su función es solo una cuestión de:En conjunto, podemos obtener un mapeo bastante agradable:
Dicho esto, el mapeo del modo visual probablemente se dejaría engañar fácilmente por una
while
o una,if
por lo que probablemente se beneficiaría de un poco de pulido. Además, mantener la selección visual puede no ser una muy buena idea ...fuente
if
,for
,while
, etc.Una solución imperfecta es usar pliegues . Doblar todo:
Dígale a Vim que no abra las áreas plegadas para los resultados de búsqueda:
Y luego abra el pliegue en la función en cuestión (
zO
).Ahora, todos los resultados para el texto buscado en una región plegada darán lugar a que Vim salte a la línea de plegado una vez, y luego continúe con el siguiente resultado.
Por ejemplo, en el caso a continuación:
La función plegada tiene muchos usos
size
, peron
no me guiará por cada uso desize
esa función.fuente
De otra manera:
use el operador de búsqueda de Osyo Manga (depende de vim-operator-user ) para buscar solo dentro del bloque actual. P.ej:
... ahora puede insertar su término de búsqueda en el indicador dado; presione
n
para ver cómo los resultados de búsqueda se limitan al movimiento / objeto de texto proporcionado actualmente. Dado que este es un operador Vim (es decir, composable), si tiene una buena función de objeto de texto, ni siquiera necesita moverse dentro del cuerpo de la definición antes de buscar, sino que usa directamente algo similarg/if
o similar.fuente