Как я могу автоматически вставить прототип в 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 в команду, чтобы вставить прототип функции в другой файл (файл с тем же именем, но с другим расширением) из любой точки вашего проекта. Если есть только один другой файл, команда сразу вставляет в этот файл; если их больше одного, вам будет предложено выбрать файл; если их нет, вас попросят указать все файлы в вашем проекте. После выбора файла в подсказке будет предложен список семантических тегов в текущем буфере, который вы можете добавить после.

Я отправил пиар в Emacs Refactor . Полный код, если вы хотите попробовать, не дожидаясь пиара: нажмите здесь .

Вот демонстрация (она начинается, когда вы видите START DEMOвнизу):

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

Вы также можете использовать только Senator для копирования и функционирования прототипа. Пока точка находится где-нибудь внутри сигнатуры функции или тела функции, запустите ее 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)
{
    .....
}

Хотя этот подход не вставляется непосредственно в буфер с тем же именем, он более применим в других случаях. Ваш вариант использования работает, только если у вас есть два файла в одном каталоге и с одинаковым именем, но с разными расширениями. Что если объявление функции и определение функции должны находиться в разных файлах с разными именами?

РЕДАКТИРОВАТЬ 2 : Вот пример для умной вставки прототипа функции с использованием семантических тегов. В настоящее время вы можете вставлять только на основе относительных позиций («до» и «после») семантических тегов верхнего уровня. Я буду обновлять , чтобы сделать пользователь , чтобы иметь возможность вставить в любом месте , где семантические теги доступны, с большим количеством позиций (то есть , когда тег является Class, он должен предложить дополнительные позиции: public, projectedа private). Демо начинается, когда вы видите START DEMOвнизу:

Снаряд-семантический-вставка-функция-prototype2

Бонус : если вы хотите создать список пустых определений функций в .cppфайле из файла заголовка, используйте member-functions.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 ";"))))))
Malabarba
источник
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). Конечно, вы можете добавить более интересные вещи, такие как создание новой линии рядом с точкой и рывок там, но это на ваш вкус.

PythonNut
источник