Come posso inserire automaticamente un prototipo in foo.h da foo.c?


11

Supponiamo che stia scrivendo un programma C in un file foo.c:

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

Voglio un comando che inserirà un prototipo di funzione corrispondente in foo.h:

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

Esistono soluzioni Emacs esistenti per questo?

Risposte:


9

AGGIORNAMENTO : ho creato il pacchetto Semantic Refactor che risolve completamente questo problema e altro ancora. Puoi guardare le demo per vedere come funziona. Il testo rimanente di questa risposta, dopo questa frase, è vecchio e messo lì solo per motivi storici.

VECCHIA RISPOSTA :

È possibile utilizzare senator-copy-tagper copiare accuratamente la firma della funzione, quindi incollarla nuovamente nel file di origine. senator-copy-tage i comandi Senator sono disponibili quando si abilita semantic-mode:

(semantic-mode 1)

Semantic è un pacchetto integrato di Emacs.

È possibile combinare Semantic Senator con Projectile in un comando per inserire il prototipo di funzione in un altro file (file con lo stesso nome ma con estensione diversa) da qualsiasi parte del progetto. Se c'è solo un altro file, il comando si inserisce immediatamente in quel file; se più di uno, viene richiesto di selezionare un file; in caso contrario, vengono richiesti tutti i file nel progetto. Dopo aver selezionato un file, un prompt offre un elenco di tag semantici nel buffer corrente che è possibile scegliere di inserire dopo.

Ho inviato una PR a Emacs Refactor . Codice completo se si desidera provare senza attendere il PR: fare clic qui .

Ecco una demo (inizia quando vedi START DEMOin basso):

proiettile-semantico-insert-function-prototipo

Puoi anche usare solo Senator per copiare e far funzionare il prototipo. Fintanto che point è in qualsiasi punto all'interno della firma della funzione o del corpo della funzione, esegui senator-copy-tag, che è associato per C-c , M-wimpostazione predefinita, copia l'intera funzione: sia la firma che il corpo. Tuttavia, è possibile incollare solo la firma se lo si desidera eseguendo il comando senator-yank-tag, che è associato per C-c , C-yimpostazione predefinita. Premendo C-yincolla l'intera firma della funzione insieme al suo corpo. senator-copy-tagfunziona anche con la firma della funzione espansa su più righe come questa:

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

Sebbene questo approccio non venga inserito direttamente nel buffer con lo stesso nome, è più applicabile in altri casi. Il tuo caso d'uso funziona solo se hai due file nella stessa directory e con lo stesso nome ma con estensioni diverse. Cosa succede se la dichiarazione di funzione e la definizione di funzione devono rimanere in file diversi con nomi diversi?

EDIT2 : ecco un esempio per l'inserimento intelligente del prototipo di funzione usando i tag semantici. Attualmente, puoi inserire solo in base alle posizioni relative ("prima" e "dopo") dei tag semantici di livello superiore. Vi aggiornerò all'utente fare per essere in grado di inserire in qualsiasi luogo in cui sono disponibili i tag semantici, con più posizioni (vale a dire quando un tag è una Class, dovrebbe offrire ulteriori posizioni: public, projectede private). La demo inizia quando vedi START DEMOin basso:

proiettile-semantico-insert-funzione-prototype2

Bonus : se si desidera generare un elenco di definizioni di funzioni vuote in un .cppfile da un file di intestazione, utilizzare member-Functions.el . Ma presto lo sostituirò con Semantic + Projectile.


3

Il seguente comando dovrebbe farlo. Ha superato i miei test e non ha dipendenze esterne.

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

2

Penso che dovrebbe funzionare quanto segue (funziona per me):

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

Ciò richiede smartparens, anche se potresti essere in grado di hackerare la tua copia sp-backward-up-sexpse ciò è inaccettabile.

Si noti inoltre che ciò inserirà l'intestazione ovunque sia stata lasciata l' (point)ultima nell'intestazione. Dato che non hai specificato dove lo volevi, ho pensato che probabilmente era il migliore. Naturalmente, se si vuole che da aggiungere alla fine, si può mettere una (end-of-buffer)prima del (yank). Ovviamente puoi aggiungere cose più fantasiose come creare una nuova linea vicino al punto e strattonarti lì, ma dipende dai tuoi gusti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.