¿Cómo puedo encontrar el paréntesis circundante (de emacs lisp)?

7

¿Hay alguna manera de averiguar el tipo de paréntesis circundante (es decir, '(', '[' o '{') alrededor del punto? Por ejemplo (usando |para representar el punto)

{ abc, | df }

debería devolver '{' y

{ abc[ | ], 123 }

debería devolver '['. Idealmente, me gustaría que también maneje comillas.


En caso de que alguien tenga curiosidad o necesite más detalles: mi objetivo es configurar el espaciado automático inteligente :en Python usando el espaciado eléctrico (también conocido como operador inteligente ). El problema es que normalmente (en python) :es el operador de división o el inicio de una declaración for / if / ..., que no debe estar rodeada de espacios. Sin embargo, dentro de un diccionario es algo así como un operador de asignación, por lo que debe estar rodeado de espacios. Entonces, tengo que verificar si el punto está dentro de un dict (es decir, dentro {}), pero no dentro de una operación de corte o cadena dentro de ese dict (es decir, no dentro []o "").


Editar:

Aquí está la función auxiliar que escribí, basada en la respuesta 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))))

Entonces, el predicado final es:

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

Edición 2:

La función anterior resultó ser demasiado lenta (a menudo causaba un retraso notable cuando :se tecleaba). Ahora estoy usando la respuesta de Stefan, que parece ser mucho más rápido.

dshepherd
fuente
1
No es una respuesta completa, pero para el caso específico de "", puede usar el incorporado in-string-p.
T. Verron

Respuestas:

10

En lugar de up-listrecomendarle, use lo (syntax-ppss)que le devolverá algún estado de análisis. Esto incluirá información sobre si está dentro de una cadena o un comentario, la posición del último "par" abierto, etc.

Por ejemplo, puedes encontrar el tipo de pareja con

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

y es de esperar que también le permita manejar comillas (marcando (nth 3 ppss)y (char-after (nth 8 ppss))).

Stefan
fuente
5

Prueba esto:

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

Tenga en cuenta que up-listpuede arrojar, por lo que también debe manejar los errores.

abo-abo
fuente
1
Me gusta la simplicidad de esta respuesta, pero resultó ser demasiado lenta en Python cuando el punto no está dentro de ningún parens (muy común con la sintaxis de espacios en blanco de Python). Presumiblemente es porque termina analizando todo el búfer en este caso.
dshepherd
1

Mientras que la respuesta preferible IMO fue dada por Stefan, aquí un ejemplo que incluye una solución que no se basa en delimitadores WRT de tabla de sintaxis: utiliza algo como

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

y una pila Ver fuente aquí

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

Andreas Röhler
fuente
0

Aquí hay una función que devuelve el paréntesis circundante, incluido el caso cuando el punto está directamente en el primer o último paréntesis (que era importante en mi caso).

Esto funciona con el lenguaje, por lo que ({[]})todo funciona en C, por ejemplo.

(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
fuente