Comment puis-je insérer automatiquement un prototype dans foo.h à partir de foo.c?

11

Supposons que j'écris un programme C dans un fichier foo.c:

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

Je veux une commande qui insérera un prototype de fonction correspondant dans foo.h:

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

Existe-t-il des solutions Emacs pour cela?

Wilfred Hughes
la source

Réponses:

9

MISE À JOUR : J'ai créé le package Semantic Refactor qui résout complètement ce problème et plus encore. Vous pouvez regarder les démos pour voir comment cela fonctionne. Le reste du texte de cette réponse, après cette phrase, est ancien et l'a mis là juste pour une raison historique.

ANCIENNE RÉPONSE :

Vous pouvez utiliser senator-copy-tagpour copier avec précision la signature de la fonction, puis la coller dans votre fichier source. senator-copy-taget les commandes Senator sont disponibles lorsque vous activez semantic-mode:

(semantic-mode 1)

Semantic est un package intégré à Emacs.

Vous pouvez combiner Semantic Senator avec Projectile dans une commande pour insérer un prototype de fonction dans un autre fichier (fichier du même nom mais avec une extension différente) de n'importe où dans votre projet. S'il n'y a qu'un autre fichier, la commande s'insère immédiatement dans ce fichier; s'il y en a plusieurs, vous êtes invité à sélectionner un fichier; s'il n'y en a pas, vous êtes invité à saisir l'intégralité des fichiers de votre projet. Après avoir sélectionné un fichier, une invite propose une liste de balises sémantiques dans le tampon actuel que vous pouvez choisir d'insérer après.

J'ai soumis un PR à Emacs Refactor . Code complet si vous voulez essayer sans attendre le PR: cliquez ici .

Voici une démo (ça commence quand on voit START DEMOen bas):

projectile-sémantique-insert-fonction-prototype

Vous pouvez également utiliser uniquement Senator pour copier et faire fonctionner le prototype. Tant que le point se trouve n'importe où à l'intérieur de la signature de fonction ou du corps de fonction, run senator-copy-tag, qui est lié C-c , M-wpar défaut, il copie la fonction entière: à la fois la signature et le corps. Cependant, vous pouvez coller uniquement la signature si vous le souhaitez en exécutant la commande senator-yank-tag, qui est liée C-c , C-ypar défaut. Appuyez sur C-ycoller toute la signature de fonction avec son corps. senator-copy-tagfonctionne même avec la signature de fonction développée sur plusieurs lignes comme ceci:

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

Bien que cette approche ne s'insère pas directement dans le tampon du même nom, elle est plus applicable dans d'autres cas. Votre cas d'utilisation ne fonctionne que si vous avez deux fichiers dans le même répertoire et avec le même nom mais des extensions différentes. Que faire si la déclaration de fonction et la définition de fonction doivent rester dans des fichiers différents avec des noms différents?

EDIT2 : Voici un exemple d'insertion intelligente d'un prototype de fonction à l'aide de balises sémantiques. Actuellement, vous ne pouvez insérer que sur la base des positions relatives ("avant" et "après") des balises sémantiques de niveau supérieur. Je vais mettre à jour à l' utilisateur de faire pour être en mesure d'insérer dans un endroit où les balises sémantiques sont disponibles, avec plusieurs positions (quand une étiquette est Class, il devrait offrir des postes supplémentaires: public, projectedet private). La démo démarre lorsque vous voyez START DEMOen bas:

projectile-semantic-insert-function-prototype2

Bonus : si vous souhaitez générer une liste de définitions de fonctions vides dans un .cppfichier à partir d'un fichier d'en-tête, utilisez member-functions.el . Mais bientôt, je vais le remplacer par Semantic + Projectile.

Tu Do
la source
3

La commande suivante devrait le faire. Il a réussi mes tests et n'a aucune dépendance externe.

(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
la source
2

Je pense que ce qui suit devrait fonctionner (cela fonctionne pour moi):

(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 ";")))

Cela nécessite smartparens, bien que vous puissiez être en mesure de pirater votre propre copie sp-backward-up-sexpsi cela est inacceptable.

Notez également que cela mettra l'en-tête là où vous avez laissé le (point)dernier dans l'en-tête. Comme vous n'avez pas précisé où vous le vouliez, j'ai pensé que c'était probablement le meilleur. Bien sûr, si vous souhaitez l'ajouter à la fin, vous pouvez mettre un (end-of-buffer)avant le (yank). Bien sûr, vous pouvez ajouter des choses plus sophistiquées, comme créer une nouvelle ligne près du point et yanking, mais c'est à votre goût.

PythonNut
la source