Formatar automaticamente colchetes

9

Estou tentando criar uma função que coloca / alinha / recua colchetes de acordo com a formatação no estilo Allman (para codificação em C).

De um modo geral, sou fã da interface do Smartparens disponível para os usuários para personalizar a funcionalidade. Eu escrevi várias outras funções usando a interface Smartparens, por isso teria uma forte preferência de não alternar pacotes neste momento. Dito isto, estou aberto a implementações independentes de pacote (por exemplo, podem defadviceser relevantes aqui?).

Para o problema em questão. Qual é o objetivo final? Vamos supor que estamos codificando e atingimos o estado representado abaixo. O símbolo de barra vertical representa o cursor; Eu digitei o cabeçalho da função e a chave de abertura {, e a Smartparens adicionou automaticamente a chave de fechamento }. Neste ponto, eu gostaria que pressionando RET...

int main {|}

... leva ao seguinte:

int main
{
    |
}

Consegui escrever a função que resulta nesse comportamento, mas ela funciona apenas para o primeiro nível de indentação (por exemplo, para nossa função principal no exemplo acima). Não consigo fazê-lo funcionar em níveis subsequentes de recuo (veja gif):

insira a descrição da imagem aqui

O código relevante está abaixo. A função não é bonita, mas acho que deve funcionar ... A última linha é a interface do Smartparens.

Alguma sugestão?


(defun my-create-newline-and-enter-sexp (&rest _ignored)
  "Open a new brace or bracket expression, with relevant newlines and indent. "
  (interactive)
  (progn
    (backward-char 2) (newline) (forward-char) (newline)     
    (indent-according-to-mode)                               
    (previous-line 2) (indent-according-to-mode)         
    (next-line) (next-line) (indent-according-to-mode)))      

(sp-local-pair 'c-mode "{" nil :post-handlers '((my-create-newline-and-enter-sexp "RET")))
homem do gelo
fonte

Respostas:

11

O Emacs-24.4 já electric-pair-modefaz uma parte do que você deseja (esse modo é muito semelhante ao autopair.el, não sei como ele se compara aos smartparens). E c-toggle-auto-newlinefaz a outra parte.

Mas, infelizmente, eles não funcionam bem juntos. Por favor, M-x report-emacs-bugpara que possamos consertar isso.

Em vez de c-toggle-auto-newline, você também pode usar electric-layout-modecom uma configuração como (setq electric-layout-rules '((?\{ . around) (?\} . around))).

Stefan
fonte
1
relatado! seria realmente bom se os dois pudessem trabalhar juntos.
iceman 30/10
7

Resolvido. A sequência de movimentos do cursor da minha primeira versão (na postagem original) foi descolada.

Como referência para futuros leitores, o código a seguir deve funcionar. Obv precisa do pacote Smartparens (que você pode obter no git-hub). Estou executando o Emacs 24.4. Funciona com o modo de indentação elétrica ativado ou desativado.

(defun my-create-newline-and-allman-format (&rest _ignored)
"Allman-style formatting for C."
  (interactive)
  (progn
    (newline-and-indent)
    (previous-line) (previous-line) (search-forward "{") (backward-char) (newline-and-indent)
    (next-line) (indent-according-to-mode)))

E você precisará incluir também o seguinte no seu arquivo init, em algum lugar após o carregamento do pacote Smartparens:

(sp-local-pair '(c-mode) "{" nil :post-handlers '((my-create-newline-and-allman-format "RET")))
homem do gelo
fonte
2
Em vez de usar coisas como previous-linecom search-forwardpara tentar descobrir novamente onde você estava, é muito melhor lembrar sua posição em uma variável e depois apenas usar goto-char.
30514 Stefan #
Essa é provavelmente a rota mais robusta. Existem funções / variáveis ​​/ etc que você acha que podem ser úteis nesse contexto? Só consigo pensar, save-excursionmas tenho certeza de que existem outras que não conheço.
iceman 30/10
0

Aqui está o código que eu uso, apenas para lhe dar mais idéias para alterar seu código:

(defun ins-c++-curly ()
  "Insert {}.
Threat is as function body when from endline before )"
  (interactive)
  (cond ((eq major-mode 'term-mode)
         (term-send-raw-string "{}")
         (term-send-raw-string "^B"))
        ((looking-back "\\()\\|try\\|else\\|const\\|:\\)$")
         (insert " {\n\n}")
         (indent-according-to-mode)
         (forward-line -1)
         (indent-according-to-mode))
        ((region-active-p)
         (let ((beg (region-beginning))
               (end (region-end)))
           (deactivate-mark)
           (goto-char beg)
           (insert "{")
           (goto-char (1+ end))
           (insert "}")))
        (t
         (insert "{}")
         (indent-according-to-mode)
         (backward-char))))

Eu prefiro o estilo de suspensórios, pois economiza espaço.

abo-abo
fonte