Como posso encontrar parênteses ao redor (do emacs lisp)?

7

Existe uma maneira de descobrir o tipo de parênteses ao redor (por exemplo, '(', '[' ou '{') ao redor do ponto? Por exemplo (usando |para representar o ponto)

{ abc, | df }

deve retornar '{' e

{ abc[ | ], 123 }

deve retornar '['. Idealmente, eu gostaria que ele também manipulasse aspas.


Caso alguém esteja curioso ou precise de mais detalhes: meu objetivo é configurar o espaçamento automático inteligente :em python usando espaçamento elétrico (também conhecido como operador inteligente ). O problema é que normalmente (em python) :é o operador de fatia ou o início de uma instrução for / if / ..., que não deve ser cercada por espaços. No entanto, dentro de um dicionário, é algo como um operador de atribuição e, portanto, deve ser cercado por espaços. Então, eu preciso verificar se o ponto está dentro de um ditado (por exemplo, dentro {}), mas não dentro de uma operação de fatia ou string dentro desse ditado (ou seja, não dentro []ou "").


Editar:

Aqui está a função auxiliar que escrevi, com base na resposta de abo-abo:

(defun enclosing-paren ()
  "Return the closing parenthesis of the enclosing parens, or nil if not inside any parens."
  (ignore-errors
    (save-excursion
      (up-list)
      (char-before))))

Então o predicado final é:

(and (not (in-string-p))
     (eq (enclosing-paren) ?\}))

Edição 2:

A função acima acabou sendo muito lenta (geralmente causava um atraso perceptível quando a :era digitada). Agora estou usando a resposta de Stefan, que parece ser muito mais rápida.

dshepherd
fonte
11
Não é uma resposta completa, mas para o caso específico de "", você pode usar o built-in in-string-p.
506 Verron

Respostas:

10

Em vez de up-listrecomendar, você utilizará o (syntax-ppss)que retornará a você algum estado de análise. Isso incluirá informações sobre se você está dentro de uma string ou comentário, a posição do último "paren" aberto, etc ...

Por exemplo, você pode encontrar o tipo de parêntese com

(let ((ppss (syntax-ppss)))
  (when (nth 1 ppss) (char-after (nth 1 ppss))))

e espero que também permita que você manipule aspas (marcando (nth 3 ppss)e (char-after (nth 8 ppss))).

Stefan
fonte
5

Tente o seguinte:

(save-excursion
  (up-list)
  (char-before))

Observe que isso up-listpode acontecer, então você também precisa lidar com erros.

abo-abo
fonte
11
Eu gosto da simplicidade desta resposta, mas ela ficou muito lenta no python quando o point não está dentro de nenhum parênteses (muito comum na sintaxe de espaço em branco do python). Presumivelmente, é porque acaba analisando todo o buffer nesse caso.
precisa saber é o seguinte
1

Embora a resposta preferida da IMO tenha sido dada por Stefan, aqui está um exemplo que inclui uma solução que não depende de delimitadores WRT da tabela de sintaxe: Ele usa algo como

 (skip-chars-backward "^{\(\[\]\)}")

e uma pilha. Veja a fonte aqui

https://github.com/emacs-berlin/general-close

Andreas Röhler
fonte
0

Aqui está uma função que retorna parênteses ao redor, incluindo o caso em que o ponto está diretamente no primeiro ou no último parêntese (o que foi importante no meu caso).

Isso funciona com o idioma, então ({[]})todos funcionam em C, por exemplo.

(defun find-surrounding-brackets (pos)
  "Return a pair of buffer positions for the opening & closing bracket positions.

Or nil when nothing is found."
  (save-excursion
    (goto-char pos)
    (when
      (or
        ;; Check if we're on the opening brace.
        (when
          ;; Note that the following check for opening brace
          ;; can be skipped, however it can cause the entire buffer
          ;; to be scanned for an opening brace causing noticeable lag.
          (and
            ;; Opening brace.
            (eq (syntax-class (syntax-after pos)) 4)
            ;; Not escaped.
            (= (logand (skip-syntax-backward "/\\") 1) 0))
          (forward-char 1)
          (if (and (ignore-errors (backward-up-list arg) t) (eq (point) pos))
            t
            ;; Restore location and fall through to the next check.
            (goto-char pos)
            nil))
        ;; Check if we're on the closing or final brace.
        (ignore-errors (backward-up-list arg) t))
      ;; Upon success, return the pair as a list.
      (list
        (point)
        (progn
          (forward-list)
          (1- (point)))))))
ideasman42
fonte