Подтвердить что ты не робот

Шаблоны С++ и Emacs: настройка отступов

Насколько я знаю в emacs, нет способа настроить уровень отступов закрывающего " > " символа списка шаблонов в С++. В настоящее время моя схема выделения в emacs делает это:

template <
    typename T1,
    typename T2,
    typename T3
    >
class X;

Я хочу что-то вроде этого:

template <
    typename T1,
    typename T2,
    typename T3
>
class X;

Установка шаблона переменной indent-args-cont в ноль приведет к отступлению символа ' > ' должным образом, но за счет исключения отдельного тела списка аргументов шаблона.

Любые предложения от гуру emacs?

EDIT:

Я немного работал со следующим хаком:

(defun indent-templates (elem)
  (c-langelem-col elem t)
  (let ((current-line
         (buffer-substring-no-properties
          (point-at-bol) (point-at-eol))))
    (if (string-match-p "^\\s-*>" current-line)
        0
        '+)))

И затем установите шаблон-args-cont для отступов-шаблонов в моей настраиваемой теме, ala:

(c-add-style "my-style"
             '("stroustrup"
                ;; ... Other stuff ...
                (template-args-cont . indent-templates))))

Но это все еще довольно плохо. Он работает большую часть времени, но иногда emacs запутывается, думая, что список шаблонов является arglist, а затем начинается веселье.

4b9b3361

Ответ 1

Лучшим решением, которое я нашел, является создание пользовательской (и относительно простой) функции отступов.

Код

(defun c++-template-args-cont (langelem)
"Control indentation of template parameters handling the special case of '>'.
Possible Values:
0   : The first non-ws character is '>'. Line it up under 'template'.
nil : Otherwise, return nil and run next lineup function."
  (save-excursion
    (beginning-of-line)
    (if (re-search-forward "^[\t ]*>" (line-end-position) t)
        0)))

(add-hook 'c++-mode-hook
          (lambda ()
            (c-set-offset 'template-args-cont
                          '(c++-template-args-cont c-lineup-template-args +))))

Это обрабатывает все случаи, с которыми я столкнулся, даже если шаблоны вложены в несколько уровней.

Как это работает

Для отступающего кода, если предоставлен список функций отступов, Emacs будет их выполнять по порядку, и если выполняемый в данный момент экземпляр возвращает nil, он будет вызывать следующий. То, что я сделал, добавляет новую функцию отступов в начало списка, которая определяет, является ли первый символ без пробелов в строке " > " , и если это так, установите отступ в позицию 0 (который выровняет его вверх с шаблоном открытия). Это также относится к случаю, когда у вас есть параметры шаблона шаблона следующим образом:

template <
  template <
    typename T,
    typename U,
    typename... Args
  > class... CS
>

потому что ему все равно, что после " > " . Таким образом, в результате того, как работает список функций отступа, если " > " не является первым символом, функция возвращает nil и вызывается обычная функция отступов.

Ответ 2

Комментарии

Я думаю, что часть проблемы заключается в том, что при создании шаблонов режим emacs CC просматривает его с той же структурой template-args-cont. Поэтому, принимая это во внимание, я расширил вашу оригинальную идею и постарался сделать это по своему вкусу; Я сделал код многословным, чтобы, надеюсь, каждый мог понять мое намерение.:) Это не должно вызывать проблем при создании экземпляра, и оно также работает для параметров шаблона шаблона! Попробуйте это, пока кто-то, у кого больше навыков Elisp, не станет лучшим решением!

Если у вас возникнут какие-либо "боевые действия" (например, чередующиеся или сломанные отступы), попробуйте перезагрузить файл cpp C-x C-v Enter и отступом снова. Иногда с параметрами шаблона шаблона emacs показывает внутренние аргументы как arglist-cont-nonempty и даже чередует их назад и вперед с template-args-const, но перезагрузка всегда восстанавливается.

Использование

Чтобы сделать то, что вы хотите, попробуйте воспользоваться приведенным ниже кодом и добавьте в свою c-offsets-alist запись:

(template-args-cont . brian-c-lineup-template-args)

и установите переменную

(setq brian-c-lineup-template-closebracket t)

Я предпочитаю немного другое выравнивание:

(setq brian-c-lineup-template-closebracket 'under)

Код

(defvar brian-c-lineup-template-closebracket 'under 
  "Control the indentation of the closing template bracket, >.
Possible values and consequences:
'under : Align directly under (same column) the opening bracket.
t      : Align at the beginning of the line (or current indentation level.
nil    : Align at the same column of previous types (e.g. col of class T).")

(defun brian-c-lineup-template--closebracket-p ()
  "Return t if the line contains only a template close bracket, >."
  (save-excursion 
    (beginning-of-line)
    ;; Check if this line is empty except for the trailing bracket, >
    (looking-at (rx (zero-or-more blank)
            ">"
            (zero-or-more blank)))))

(defun brian-c-lineup-template--pos-to-col (pos)
  (save-excursion
    (goto-char pos)
    (current-column)))

(defun brian-c-lineup-template--calc-open-bracket-pos (langelem)
  "Calculate the position of a template declaration opening bracket via LANGELEM."
  (save-excursion 
    (c-with-syntax-table c++-template-syntax-table
      (goto-char (c-langelem-pos langelem))
      (1- (re-search-forward "<" (point-max) 'move)))))

(defun brian-c-lineup-template--calc-indent-offset (ob-pos)
  "Calculate the indentation offset for lining up types given the opening 
bracket position, OB-POS."
  (save-excursion
    (c-with-syntax-table c++-template-syntax-table
      ;; Move past the opening bracket, and check for types (basically not space)
      ;; if types are on the same line, use their starting column for indentation.
      (goto-char (1+ ob-pos))
      (cond ((re-search-forward (rx 
                 (or "class"
                     "typename"
                     (one-or-more (not blank))))
                (c-point 'eol)
                'move)
         (goto-char (match-beginning 0))
         (current-column))
        (t
         (back-to-indentation)
         (+ c-basic-offset (current-column)))))))

(defun brian-c-lineup-template-args (langelem)
  "Align template arguments and the closing bracket in a semi-custom manner."
  (let* ((ob-pos (brian-c-lineup-template--calc-open-bracket-pos langelem))
     (ob-col (brian-c-lineup-template--pos-to-col ob-pos))
     (offset (brian-c-lineup-template--calc-indent-offset ob-pos)))

    ;; Optional check for a line consisting of only a closebracket and
    ;; line it up either at the start of indentation, or underneath the
    ;; column of the opening bracket
    (cond ((and brian-c-lineup-template-closebracket
          (brian-c-lineup-template--closebracket-p))
         (cond ((eq brian-c-lineup-template-closebracket 'under)
            (vector ob-col))
           (t
            0)))
        (t
         (vector offset)))))

Ответ 3

Это другой подход, а затем изменение вкладок, но как насчет использования системы фрагментов, например Yasnippet (см. примеры здесь).

Единственная проблема заключается в том, что если вы переформатируете документ "M-x index-region" (или этот раздел), он, вероятно, вернется к другим правилам табуляции.