Fechar todos os parênteses pendentes

14

Ao escrever códigos lisp, às vezes tenho uma expressão aninhada e tudo o que quero é inserir todos os parênteses de fechamento ausentes. No momento, estou apenas inserindo-os até obter um parêntese incompatível, mas não é muito eficiente.
Existe algum comando para inserir todos os parênteses ausentes?

Para sua informação, estou usando o smartparens para inserir automaticamente os pares correspondentes. Ainda assim, às vezes eu só preciso fazer isso.

rlazo
fonte
2
FWIW, Franz Lisp (antes de CL) tinha um recurso em que um ]agia como um parêntese super-direito, fechando todas as parênteses abertas, conforme solicitado.
Tirou
2
Eu usei a mesma metodologia no passado. Desde então, comecei a usar o paredit , o que interrompe o problema antes de começar. A única ressalva é que colar no código não recebe o mesmo tratamento de balanceamento.
elarson

Respostas:

6

Aqui está uma função que fecha todos os parênteses não fechados e outros pares correspondentes. Ele se baseia na análise sexp do Emacs. Ele suporta apenas pares correspondentes de um caractere; portanto, algo como {-será fechado }, não -}. Para Lisp, isso não importa.

(defun close-all-parentheses ()
  (interactive "*")
  (let ((closing nil))
    (save-excursion
      (while (condition-case nil
         (progn
           (backward-up-list)
           (let ((syntax (syntax-after (point))))
             (case (car syntax)
               ((4) (setq closing (cons (cdr syntax) closing)))
               ((7 8) (setq closing (cons (char-after (point)) closing)))))
           t)
           ((scan-error) nil))))
    (apply #'insert (nreverse closing))))
Gilles 'SO- parar de ser mau'
fonte
IIUC, isso exige que o ponto não esteja dentro de nenhum conjunto de parênteses correspondentes. Fiquei com a impressão de que o OQ precisava trabalhar com alguns dentro de uma expressão lisp, onde parênteses feitos serão incompatíveis, mas outros não.
Malabarba
@ Malabarba Isso fecha todos os parênteses abertos anteriormente, se eles já tinham parênteses de fechamento correspondentes após o ponto ou não. É assim que entendo a pergunta, mas é certo que não está claro sobre esse ponto. Sob sua interpretação, onde os delimitadores de fechamento seriam inseridos? Por exemplo ([-!-foo], com , você insere ])no ponto ou )depois foo]?
Gilles 'SO- stop be evil'
do meu entendimento, se você tiver ([-!-foo], gostaria de inserir )depois foo]. Mas eu posso estar errado, é claro. Talvez o @rlazo possa elaborar.
Malabarba
para o meu caso de uso, @Gilles está certo, não me importo se os delimitadores estiverem fechados após o ponto, quero fechar tudo antes do ponto.
Rlazo # 9/14
3

Eu descobri que se você tiver o slime instalado, existe um comando para fazer isso, chamado slime-close-all-parens-in-sexp

rlazo
fonte
Hmm ... então isso parece fechar na linha atual. Seria bom se houvesse uma abordagem que fechasse "o bloco atual". Isso pode ser alcançado indo até o final do arquivo e depois movendo o sexp para trás até que nada seja encontrado.
Att Righ
1

Uma maneira muito primitiva (e quase certamente errada) de fazer isso seria

(defun buffer-needs-parens-fixing ()
  (save-excursion
    (condition-case nil
        (check-parens)
      (error (point)))))

(defun buffer-fix-parens ()
  (interactive)
  (while (buffer-needs-parens-fixing)
    (insert ")")))

Entre outras limitações, assume que todos os parênteses que precisam ser inseridos são:

  • fechando
  • necessário no local atual

Eu acho que pode ser apenas o suficiente para ser útil para o seu caso de uso específico

Sigma
fonte
Isso fica preso em um loop infinito se você tiver muitos parênteses de fechamento.
Emil Vikström
@ EmilVikström sim, isso não é de fato compatível com a minha primeira limitação declarado :)
Sigma