¿Cómo puedo insertar automáticamente un prototipo en foo.h desde foo.c?

11

Supongamos que estoy escribiendo un programa en C en un archivo foo.c:

int add_numbers(int x, int y, int z) {
    // Very complex implementation here.
    return x + y + z;
}

Quiero un comando que inserte un prototipo de función correspondiente en foo.h:

int add_numbers(int x, int y, int z);

¿Existen soluciones Emacs existentes para esto?

Wilfred Hughes
fuente

Respuestas:

9

ACTUALIZACIÓN : creé el paquete Semantic Refactor que resuelve completamente este problema y más. Puede ver las demostraciones para ver cómo funciona. El texto restante de esta respuesta, después de esta oración, es antiguo y lo puso allí solo por razones históricas.

ANTIGUA RESPUESTA :

Puede usar senator-copy-tagpara copiar con precisión la firma de la función y luego pegarla nuevamente en su archivo fuente. senator-copy-tagy los comandos Senator están disponibles cuando habilita semantic-mode:

(semantic-mode 1)

Semantic es un paquete integrado de Emacs.

Puede combinar Senador semántico con proyectil en un comando para insertar el prototipo de la función en otro archivo (archivo con el mismo nombre pero diferente extensión) desde cualquier parte de su proyecto. Si solo hay otro archivo, el comando se inserta inmediatamente en ese archivo; si hay más de uno, se le solicita que seleccione un archivo; Si no hay ninguno, se le solicitarán los archivos completos de su proyecto. Después de seleccionar un archivo, un mensaje ofrece una lista de etiquetas semánticas en el búfer actual que puede elegir insertar después.

Envié un PR a Emacs Refactor . Código completo si quieres probar sin esperar al RP: haz clic aquí .

Aquí hay una demostración (comienza cuando ves START DEMOen la parte inferior):

proyectil-semántico-insertar-función-prototipo

También puede usar solo Senator para copiar y funcionar el prototipo. Siempre que el punto esté en algún lugar dentro de la firma de la función o el cuerpo de la función, ejecutar senator-copy-tag, que está vinculado C-c , M-wde forma predeterminada, copia toda la función: tanto la firma como el cuerpo. Sin embargo, puede pegar solo la firma si lo desea ejecutando el comando senator-yank-tag, que está vinculado C-c , C-yde forma predeterminada. Al presionar C-ypegar la firma de la función completa junto con su cuerpo. senator-copy-tagincluso funciona con la firma de función expandida en varias líneas como esta:

void 
func(int a,
     int b, 
     int c)
{
    .....
}

Aunque este enfoque no se inserta directamente en el búfer con el mismo nombre, es más aplicable en otros casos. Su caso de uso solo funciona si tiene dos archivos en el mismo directorio y con el mismo nombre pero con extensiones diferentes. ¿Qué sucede si la declaración de la función y la definición de la función deben permanecer en diferentes archivos con diferentes nombres?

EDIT2 : Aquí hay un ejemplo para la inserción inteligente del prototipo de función usando etiquetas semánticas. Actualmente, solo puede insertar en función de las posiciones relativas ("antes" y "después") de las etiquetas semánticas de nivel superior. Voy a actualizar a los usuarios hacer para ser capaz de insertar en cualquier lugar donde las etiquetas semánticas están disponibles, con más posiciones (es decir, cuando una etiqueta es una Class, debe ofrecer puestos adicionales: public, projectedy private). La demostración comienza cuando ves START DEMOen la parte inferior:

proyectil-semántico-insert-function-prototype2

Bonificación : si desea generar una lista de definiciones de funciones vacías en un .cpparchivo a partir de un archivo de encabezado, use member-functions.el . Pero pronto, lo reemplazaré con Semantic + Projectile.

Tu Do
fuente
3

El siguiente comando debería hacerlo. Pasó mis pruebas y no tiene dependencias externas.

(defun endless/copy-proto-to-header-file ()
  (interactive)
  (save-excursion
    ;; c-mode's `beginning-of-defun' should be robust enough.
    (beginning-of-defun)
    (let ((l (point)))
      (search-forward-regexp " *{")
      (let ((proto (buffer-substring l (match-beginning 0))))
        (ff-find-other-file)
        ;; If other file is already open, we don't want to move point.
        (save-excursion
          (goto-char (point-max))
          ;; Do some more movement here if you want.
          (insert "\n" proto ";"))))))
Malabarba
fuente
2

Creo que lo siguiente debería funcionar (funciona para mí):

(defun c-copy-function-signature-to-header ()
  (interactive)
  (save-excursion
    (let ((last-point -1))
      (while (/= (point) last-point)
        (setq last-point (point))
        (sp-backward-up-sexp))
      (kill-ring-save (point) (line-beginning-position))
      (ff-find-other-file)
      (yank)
      ;; clean whitespace between closing paren and opening curly 
      (delete-trailing-whitespace
        (line-beginning-position)
        (line-end-position))
      (insert ";")))

Esto requiere smartparens, aunque es posible que pueda hackear su propia copia de sp-backward-up-sexpsi eso es inaceptable.

También tenga en cuenta que esto colocará el encabezado donde haya dejado el (point)último en el encabezado. Como no especificaste dónde lo querías, pensé que probablemente era lo mejor. Por supuesto, si desea que se agregue al final, puede poner un (end-of-buffer)antes del (yank). Por supuesto, puede agregar cosas más elegantes como crear una nueva línea cerca del punto y tirar de allí, pero eso depende de su gusto.

PythonNut
fuente