2011-10-20 21 views
44

O ile wiem w emacs, nie ma możliwości dostosowania poziomu wcięcia zamykającego znaku ">" listy szablonów w C++. Obecnie mój program emacs wcięcie robi to:C++ Szablony i Emacs: Dostosowywanie wcięcia

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

Co chcę jest coś takiego:

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

Ustawianie wcięcia zmienne Template-args-CONT do zera będzie wciąć znak '>' prawidłowo, ale kosztem odwinięcia rzeczywistej treści listy argumentów szablonu.

Jakieś sugestie od guru emacs?

EDIT:

mam to trochę pracy z następującym Hack:

(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 
     '+))) 

a następnie ustawiając Template-args-cd do indent-szablony w moim niestandardowego motywu, ala:

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

Ale nadal jest dość wadliwy. Działa przez większość czasu, ale czasami emacs myli się myśląc, że lista szablonów jest arglistą, a następnie pojawia się wesołość.

+1

Nie jestem pewien, czy jest to możliwe, ale jeśli można znaleźć informacje na tej stronie: http://www.gnu.org/software/emacs/manual/html_mono/ccmode.html#Customizing-Indentation – rve

+0

Właściwie , Myślę, że może to być możliwe, jeśli napiszesz własną funkcję line-up. Dokument z mojego wcześniejszego komentarza podaje więcej informacji na ten temat. – rve

+6

Zauważ, że Emacs C++ - tryb zazwyczaj okresowo myli się z powodu argumentów szablonu, więc może to nie być problem z kodem ... [aby być sprawiedliwym, jest to naprawdę trudne do uzyskania, ze względu na wiele znaczeń '<' and '>' w C++ (czasami jako zrównoważony separator, czasami jako operator), chyba że robisz dużo więcej rzeczywistego analizowania niż C++ - tryb robi ...] – snogglethorpe

Odpowiedz

2

Najlepszym rozwiązaniem, które znalazłem jest pisanie na zamówienie (i stosunkowo proste) Funkcja wcięcia.

Kodeks

(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 +)))) 

uchwyty Ta wszystkich przypadkach, że mam natknąć nawet szablony zagnieżdżone kilka poziomów głębokości.

Jak to działa

dla kodu wcięć, jeśli lista funkcji wcięcie jest zapewnione, wtedy Emacs spróbuje je w porządku i jeśli ktoś aktualnie wykonywane powraca nil, będzie powoływać się na następny. To, co zrobiłem, to dodano nową funkcję wcięcia na początku listy, która wykrywa, czy pierwszy nie biały znak na linii to ">", a jeśli tak, ustaw wcięcie na pozycję 0 (która ustawi ją w linii z szablonem otwarcia). Obejmuje to również przypadek, w którym masz parametry szablonu szablonu w następujący sposób:

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

, ponieważ nie obchodzi go, co jest po ">". W związku z tym, jak działa lista funkcji wcięcia, jeśli ">" nie jest pierwszym znakiem, funkcja zwraca nil i wywoływana jest zwykła funkcja wcięcia.

0

To inne podejście niż zmiana kart, ale co z użyciem systemu snippet, takiego jak Yasnippet (zobacz przykłady here).

Jedynym problemem jest to, że jeśli ponownie sformatujesz dokument "region indeksowy M-x" (lub tę sekcję), prawdopodobnie powróci on do reguł innych kart.

1

Komentarze

myślę część problem wystąpi to, że podczas wystąpienia szablony, emacs tryb CC postrzega go z taką samą template-args-cont struktury. Biorąc to pod uwagę, rozszerzyłem swój pierwotny pomysł i próbowałem dostosować go do własnych upodobań; Zrobiłem kod verbose, więc mam nadzieję, że wszyscy zrozumieją moją intencję. :) Nie powinno to powodować problemów podczas tworzenia instancji, a także wydaje się działać dla parametrów szablonu szablonu! Wypróbuj to, aż ktoś z większą ilością umiejętności Elisp może zapewnić lepsze rozwiązanie!

Jeśli wystąpi 'Walka' (tj przemienne lub uszkodzony wcięcia), spróbuj ponownie załadować plik cpp C-xC-vWprowadź i wcięć ponownie. Czasami przy szablonowych szablonach parametrów emacs pokazuje wewnętrzne argumenty jako arglist-cont-nonempty, a nawet naprzemiennie iz powrotem z template-args-const, ale reload zawsze przywracany stan.

Wykorzystanie

Aby zrobić to, co chcesz spróbować się stosując poniższy kod i dodając do c-offsets-alist wpisu:

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

i ustawić zmienną

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

Właściwie wolę nieco inne ustawienie:

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

Kod

(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))))) 
+0

Wow, dziękuję za to. Spróbuję przez weekend, jeśli będę miał trochę czasu (w trakcie przeprowadzki). – bstamour