Як я можу автоматично вставити прототип у foo.h від foo.c?


11

Припустимо, я записую програму C у файл foo.c:

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

Я хочу команду, яка вставить відповідний прототип функції у foo.h:

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

Чи існують для цього рішення Emacs?

Відповіді:


9

ОНОВЛЕННЯ : Я створив пакет Semantic Refactor, який повністю вирішує цю проблему та інше. Ви можете подивитися демо, щоб побачити, як це працює. Текст цієї відповіді, що залишився після цього речення, є старим і розміщується там лише з історичної причини.

СТАРИЙ ВІДПОВІДЬ :

Ви можете senator-copy-tagточно скопіювати підпис функції, а потім вставити назад у вихідний файл. senator-copy-tagі команди Senator доступні, коли ви вмикаєте semantic-mode:

(semantic-mode 1)

Semantic - це вбудований пакет Emacs.

Ви можете поєднати Semantic Senator з Projectile в команду, щоб вставити прототип функції в інший файл (файл з тим же ім'ям, але з різним розширенням) з будь-якого місця вашого проекту. Якщо є лише один інший файл, команда вставляється негайно у цей файл; якщо їх більше, вам буде запропоновано вибрати файл; якщо цього немає, вам буде запропоновано ввести всі файли у вашому проекті. Після вибору файлу підказка пропонує список семантичних тегів у поточному буфері, який ви можете вставити після.

Я подав PR в Emacs Refactor . Повний код, якщо ви хочете спробувати, не чекаючи PR: натисніть тут .

Ось демонстрація (вона починається, коли ви бачите START DEMOвнизу):

снаряд-семантичний-вставка-функція-прототип

Ви також можете використовувати лише сенатор для копіювання та функціонування прототипу. Поки точка знаходиться де-небудь всередині функції підпису або тіла функції, запустіть senator-copy-tag, який C-c , M-wза замовчуванням пов'язаний, він копіює всю функцію: і підпис, і тіло. Однак ви можете вставити лише підпис, якщо хочете, запустивши команду senator-yank-tag, яка зв'язана C-c , C-yза замовчуванням. При натисканні C-yвставити всю підпис функції разом з її корпусом. senator-copy-tagнавіть працює з функцією підпису, розширеною на декілька рядків, як це:

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

Хоча цей підхід не вставляється безпосередньо в буфер з такою ж назвою, він більше застосований в інших випадках. Ваш регістр використання працює лише в тому випадку, якщо ви маєте два файли в одному каталозі та з тим самим іменем, але різні розширення. Що робити, якщо декларація функції та визначення функції повинні знаходитись у різних файлах з різними іменами?

EDIT2 : Ось приклад розумної вставки прототипу функції за допомогою семантичних тегів. Наразі ви можете вставляти лише на основі відносних позицій ("до" та "після") семантичних тегів верхнього рівня. Я буду оновлювати , щоб зробити користувач , щоб мати можливість вставити в будь-якому місці , де семантичні теги доступні, з великою кількістю позицій (тобто , коли тег є Class, він повинен запропонувати додаткові позиції: public, projectedа private). Демонстрація демонструється, коли ви бачите START DEMOвнизу:

снаряд-семантичний-вставка-функція-прототип2

Бонус : Якщо ви хочете сформувати список пустих визначень функцій у .cppфайлі із заголовкового файлу, використовуйте member-функции.el . Але незабаром я заміню його на Semantic + Projectile.


3

Наступна команда повинна це зробити. Він пройшов мої тести і не має зовнішніх залежностей.

(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

Я думаю, що наступне має працювати (для мене це працює):

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

Це вимагає smartparens, хоча, можливо, ви зможете зламати власну копію, sp-backward-up-sexpякщо це неприйнятно.

Також зауважте, що це дозволить розмістити заголовок там, де ви залишили (point)останній у заголовку. Оскільки ви не вказали, де цього хочете, я подумав, що це, мабуть, найкраще. Звичайно, якщо ви хочете, щоб він додався в кінці, ви можете поставити (end-of-buffer)перед (yank). Звичайно, ви можете додати більш фантазійні речі, такі як створення нової лінії біля пункту і тузання там, але це на ваш смак.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.