Шаблоны С++ и 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, а затем начинается веселье.
Ответы
Ответ 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" (или этот раздел), он, вероятно, вернется к другим правилам табуляции.