Различные стили отступов для разных проектов

29

Я работаю над множеством различных C-проектов с уникальными стилями отступов. Как заставить Emacs выполнять настройки отступов для каждого проекта, не загрязняя деревья проекта исходными .dir-locals.elфайлами? Я хочу сопоставить проекты, используя их пути на диске.

artagnon
источник
2
Как насчет использования EditorConfig вместо .dir-locals.el. Может быть, коллеги хотели бы эту идею?
welldan97

Ответы:

21

.dir-locals.el мой предпочтительный метод, когда это возможно, особенно когда он применяется ко всем пользователям Emacs, работающим над этим проектом.

Для проектов, которые враждебны пользователям Emacs или иным образом не хотят .dir-locals.elфайлы, или если вы хотите иметь личные предпочтения (предположительно, не отступы), которые не должны применяться к другим людям, если вы используете распределенную систему контроля версий, опция всегда работать в личных ветках, которые есть у вас .dir-locals.el. Однако я не знаю, как использовать DCVS, чтобы сделать это безболезненно.

Другой вариант - не проверять .dir-locals.elфайлы. Например, с помощью git добавьте его в .git/info/exclude. Конечно, это больно, когда у вас много проверок проекта.

То, что я сделал, где .dir-locals.elне было выбора, - это добавление ловушки, которая сравнивает buffer-file-nameизвестные значения.

(defvar guessed-project nil)
(make-variable-buffer-local 'guessed-project)
(defun guess-project-from-file-name ()
  (save-match-data
    (setq guessed-project
          (cond
           ((string-match "/linux-kernel/" buffer-file-name)
            'linux-kernel)
           ((string-match "/gnu/" buffer-file-name)
            'gnu)
           ; etc.
          ))))
(defun c-my-project-hook ()
  (guess-project-from-file-name)
  (case guessed-project
    ((gnu) (c-sty-style 'gnu))
    ((linux-kernel) (c-sty-style 'linux))
  ))
(add-hook 'c-mode-hook 'c-my-project-hook)

(Предупреждение: код набран прямо в моем браузере, поскольку у меня нет доступа к моему настоящему коду прямо сейчас.)

Жиль "ТАК - перестань быть злым"
источник
2
Добавление .dir-locals.elв .git/info/excludeкажется хорошим вариантом.
Шости
Что плохого в том, чтобы добавить его .gitignoreв корневой каталог проекта?
Squidly
@ Ничего, но некоторые проекты не хотят, чтобы там были файлы, относящиеся к редактору.
Жиль "ТАК - перестать быть злым"
Для пользователей git вы можете добавить .dir-locals.elсвой глобальный gitignore по адресу ~/.config/git/ignore.
Джереми Хейлер
7

Вы не можете убедить вышестоящие проекты, такие как llvm и linux, зарегистрироваться .dir-locals.el.

Выработанное решение проблемы:

(defmacro define-new-c-style (name derived-from style-alist match-path)
  `(progn
     (c-add-style ,name
                  '(,derived-from ,@style-alist))
     (add-hook 'c-mode-hook
               (lambda ()
                 (let ((filename (buffer-file-name)))
                   (when (and filename
                              (string-match (expand-file-name ,match-path) filename))
                     (c-set-style ,name)))))))

Используется следующим образом:

(define-new-c-style "llvm" "gnu" ((fill-column . 80)
                                  (c++-indent-level . 2)
                                  (c-offsets-alist . ((innamespace 0))))
  "~/src/llvm")

(define-new-c-style "emacs" "gnu" nil "~/src/emacs")

У меня есть похожий макрос для других языковых режимов.

artagnon
источник
6

Распространение .dir-locals.el в разных проектах сложно поддерживать.

Мой способ довольно прост, поместите весь код в один ~ / .custom.el.

По сути, код будет запускаться в режиме prog-mode-hook (или your-what-major-mode-hook) и выполнять следующие действия:

  • проанализировать, содержит ли полный путь к файлу конкретное имя проекта
  • если true, тогда выполните настройку для этого проекта (включая настройку отступа).

Я успешно использую этот метод в течение одного года.

Вот код (вызовите my-setup-develop-environment в prog-mode-hook):

(defun my-project-name-contains-substring (REGEX)
  (let ((dir (if (buffer-file-name)
                 (file-name-directory (buffer-file-name))
               "")))
    (string-match-p REGEX dir)))

(defun my-office-code-style ()
  (interactive)
  (message "Office code style!")
  ;; web development
  (setq coffee-tab-width 4)
  (setq javascript-indent-level 4)
  (setq js-indent-level 4)
  (setq js2-basic-offset 4)
  (setq web-mode-indent-style 4)
  (setq web-mode-markup-indent-offset 4)
  (setq web-mode-css-indent-offset 4)
  (setq web-mode-code-indent-offset 4)
  )

(defun my-personal-code-style ()
  (interactive)
  (message "My personal code style!")
  (setq coffee-tab-width 4)
  (setq javascript-indent-level 2)
  (setq js-indent-level 2)
  (setq js2-basic-offset 2)
  (setq web-mode-indent-style 2)
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-code-indent-offset 2)
  )

(defun my-setup-develop-environment ()
  (interactive)
  (cond
   ;; company's project for ttag
   ((my-project-name-contains-substring "commerical-proj1")
    (my-office-code-style))
   ((my-project-name-contains-substring "hobby-proj1")
    (my-personal-code-style))
  )
)
(add-hook 'prog-mode-hook 'my-setup-develop-environment)
чен бен
источник
2

Нормальный способ сделать это с помощью .dir-locals. Вот почему они были введены в первую очередь. Почему бы нет? Насколько мне известно, большинство инструментов, связанных с проектом, обычно хранят свои конфиги в корневом каталоге проекта: git, svn, Eclipse и многие другие ...

Только не забудьте добавить файл .gitignoreили подобное.

Влад
источник