В режиме C / C ++ в Emacs измените грань кода в #if 0 ... # endif блоке, чтобы комментировать грань - PullRequest
12 голосов
/ 28 декабря 2010

Я пытаюсь добавить функциональность, найденную в некоторых других редакторах кода, в мою конфигурацию Emacs, в результате чего код C / C ++ в пределах #if 0 ... # endif блоков автоматически устанавливается на лицо / шрифт комментария. На основании моего тестирования cpp-highlight-mode делает что-то вроде того, что я хочу, но требует действий пользователя. Похоже, что привязка к функциональности блокировки шрифтов является правильным вариантом, чтобы сделать поведение автоматическим.

Я успешно следовал примерам в документации GNU, чтобы изменить внешний вид однострочных регулярных выражений. Например:

(add-hook 'c-mode-common-hook
  (lambda ()
    (font-lock-add-keywords nil
      '(("\\<\\(FIXME\\|TODO\\|HACK\\|fixme\\|todo\\|hack\\)" 1 
        font-lock-warning-face t)))))

отлично работает, чтобы выделить ключевые слова отладки в любом месте файла. Однако у меня возникают проблемы с совпадением #if 0 ... # endif в виде многострочного регулярного выражения. В этом посте я нашел некоторую полезную информацию ( Как составить регион, такой как "<? Php foo; bar;?>" ), в котором говорилось, что Emacs должен быть указан специально для разрешения многострочных совпадений. Но этот код:

(add-hook 'c-mode-common-hook
  (lambda ()
    '(progn
      (setq font-lock-multiline t)
      (font-lock-add-keywords nil
        '(("#if 0\\(.\\|\n\\)*?#endif" 1
          font-lock-comment-face t))))))

все еще не работает для меня. Возможно, мое регулярное выражение неверно (хотя, похоже, оно работает с использованием M-x re-builder ), я испортил свой синтаксис или полностью придерживаюсь неправильного подхода. Я использую Aquamacs 2.1 (который основан на GNU Emacs 23.2.50.1) на OS X 10.6.5, если это имеет значение.

Буду признателен за любую помощь!

1 Ответ

15 голосов
/ 29 декабря 2010

Даже если бы вы работали с многострочным регулярным выражением, у вас все равно были бы проблемы с вложенными #ifdef/#endif, поскольку он остановил бы блокировку шрифта при первом #endif.Этот код работает, хотя я не уверен, будет ли заметное замедление для больших файлов:

(defun my-c-mode-font-lock-if0 (limit)
  (save-restriction
    (widen)
    (save-excursion
      (goto-char (point-min))
      (let ((depth 0) str start start-depth)
        (while (re-search-forward "^\\s-*#\\s-*\\(if\\|else\\|endif\\)" limit 'move)
          (setq str (match-string 1))
          (if (string= str "if")
              (progn
                (setq depth (1+ depth))
                (when (and (null start) (looking-at "\\s-+0"))
                  (setq start (match-end 0)
                        start-depth depth)))
            (when (and start (= depth start-depth))
              (c-put-font-lock-face start (match-beginning 0) 'font-lock-comment-face)
              (setq start nil))
            (when (string= str "endif")
              (setq depth (1- depth)))))
        (when (and start (> depth 0))
          (c-put-font-lock-face start (point) 'font-lock-comment-face)))))
  nil)

(defun my-c-mode-common-hook ()
  (font-lock-add-keywords
   nil
   '((my-c-mode-font-lock-if0 (0 font-lock-comment-face prepend))) 'add-to-end))

(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

РЕДАКТИРОВАТЬ: Учитывать #else

РЕДАКТИРОВАТЬ # 2: Niftier код для обработки произвольного вложения if / else / endif's

...