¿Cómo deshabilito ffap (buscar archivo en el punto) cuando los dos primeros caracteres que no son espacios en una línea son '//'?

8

En Verilog / C / C ++, los comentarios pueden comenzar con //.

Aquí hay un comentario de ejemplo, //This is a comment

Me gusta usar la función find-file-at-point . Si mi cursor está en el nombre del archivo en `include "some_file.v".

Pero si mi cursor está en el comentario de ejemplo anterior y si C-x C-fpresiono, ¡emacs intenta abrir un camino tentativo //This!

¿Cómo evito selectivamente que se active find-file-at-point ? En este caso, cuando el modo principal es verilog-mode, ¿cómo NO lo hago find-file-at-pointcuando mi cursor está en una línea donde están los primeros 2 caracteres que no son espacios //?

Kaushal Modi
fuente
Yo no entiendo muy bien el caso de uso que ... lo que se reasigna C-x C-fa ffapo para una envoltura alrededor ffap?
T. Verron
Verifique la función asignada para su C-x C-f(por C-h kRET C-x C-f). Debería decir que "ejecuta el comando" find-file.
caisah
No puedo reproducir esto en mi 24.3.1 GNU Emacs. ¿Quizás este error (como señala @Sigma) ya se ha resuelto?
remvee
2
@remvee La find-file-at-pointfunción está deshabilitada de manera predeterminada. Lo tengo habilitado a través de ido. Tengo (setq ido-use-filename-at-point 'guess)en mi config.
Kaushal Modi

Respuestas:

9

Esto es un poco decepcionante, porque ffap.eltiene un código que debería hacer exactamente eso:

 ;; Immediate rejects (/ and // and /* are too common in C/C++):
     ((member name '("" "/" "//" "/*" ".")) nil)

Pero desafortunadamente, depende de que haya un espacio después del separador de comentarios.

También es muy decepcionante, porque los marcadores de comentarios nunca deberían ser parte de una cadena en el punto. Así que aquí hay una versión parcheada ffap-string-at-pointque trata de ignorar sistemáticamente esos marcadores

(require 'ffap)
(defun ffap-string-at-point (&optional mode)
  (let* ((args
      (cdr
       (or (assq (or mode major-mode) ffap-string-at-point-mode-alist)
           (assq 'file ffap-string-at-point-mode-alist))))
         next-comment
     (pt (point))
     (beg (if (use-region-p)
          (region-beginning)
        (save-excursion
          (skip-chars-backward (car args))
          (skip-chars-forward (nth 1 args) pt)
                  (save-excursion
                    (setq next-comment
                          (progn (comment-search-forward (line-end-position) t)
                                 (point))))
          (point))))
     (end (if (use-region-p)
          (region-end)
        (save-excursion
          (skip-chars-forward (car args))
          (skip-chars-backward (nth 2 args) pt)
          (point)))))
  (when (> end next-comment)
    (setq beg next-comment))
  (setq ffap-string-at-point
      (buffer-substring-no-properties
       (setcar ffap-string-at-point-region beg)
       (setcar (cdr ffap-string-at-point-region) end)))))

Por efecto secundario, soluciona su problema, pero es mucho más general. Me pregunto si tal solución debería integrarse en sentido ascendente.

Sigma
fuente
Se agregó el (require 'ffap). Me di cuenta de que este parche no estaba siendo efectivo en emacs init, ya que ffapprobablemente se carga automáticamente ... lo que no sucede hasta que interactivamente lo hagofind-file
Kaushal Modi
Agradecería una solución aguas arriba.
wasamasa
2
@wasamasa Hecho: git.savannah.gnu.org/cgit/emacs.git/commit/…
Kaushal Modi el
4

Gracias a la solución publicada por @Sigma . Tuve esa solución en mi configuración durante más de 2 años, y finalmente la envié como parche a emacs upstream.

Comprometerse en emacs master: e472cfe8


Esto es lo que hace efectivamente el parche:

(defun modi/ffap-string-at-point (&optional mode)
  "Return a string of characters from around point.

MODE (defaults to value of `major-mode') is a symbol used to look up
string syntax parameters in `ffap-string-at-point-mode-alist'.

If MODE is not found, we use `file' instead of MODE.

If the region is active,return a string from the region.

If the point is in a comment, ensure that the returned string does not contain
the comment start characters (especially for major modes that have '//' as
comment start characters). https://debbugs.gnu.org/cgi/bugreport.cgi?bug=24057

|-----------------------------------+---------------------------------|
| Example string in `c-mode' buffer | Returned `ffap-string-at-point' |
|-----------------------------------+---------------------------------|
| ▮//tmp                            | tmp                             |
| //▮tmp                            | tmp                             |
| ▮///tmp                           | /tmp                            |
| //▮/tmp                           | /tmp                            |
| ▮////tmp                          | //tmp                           |
| ////▮tmp                          | //tmp                           |
| ▮// //tmp                         | (empty string) \"\"             |
| // ▮/tmp                          | /tmp                            |
| // ▮//tmp                         | //tmp                           |
|-----------------------------------+---------------------------------|

Set the variables `ffap-string-at-point' and `ffap-string-at-point-region'.

When the region is active and larger than `ffap-max-region-length',
return an empty string, and set `ffap-string-at-point-region' to '(1 1)."
  (let* ((args
          (cdr
           (or (assq (or mode major-mode) ffap-string-at-point-mode-alist)
               (assq 'file ffap-string-at-point-mode-alist))))
         (region-selected (use-region-p))
         (pt (point))
         (beg (if region-selected
                  (region-beginning)
                (save-excursion
                  (skip-chars-backward (car args))
                  (skip-chars-forward (nth 1 args) pt)
                  (point))))
         (end (if region-selected
                  (region-end)
                (save-excursion
                  (skip-chars-forward (car args))
                  (skip-chars-backward (nth 2 args) pt)
                  (point))))
         (region-len (- (max beg end) (min beg end))))

    ;; If the initial characters of the to-be-returned string are the
    ;; current major mode's comment starter characters, *and* are
    ;; not part of a comment, remove those from the returned string
    ;; (Bug#24057).
    ;; Example comments in `c-mode' (which considers lines beginning
    ;; with "//" as comments):
    ;;  //tmp - This is a comment. It does not contain any path reference.
    ;;  ///tmp - This is a comment. The "/tmp" portion in that is a path.
    ;;  ////tmp - This is a comment. The "//tmp" portion in that is a path.
    (when (and
           ;; Proceed if no region is selected by the user.
           (null region-selected)
           ;; Check if END character is part of a comment.
           (save-excursion
             (nth 4 (syntax-ppss end))))
      ;; Move BEG to beginning of comment (after the comment start
      ;; characters), or END, whichever comes first.
      (save-excursion
        (let ((state (syntax-ppss beg)))
          ;; (nth 4 (syntax-ppss)) will be nil for comment start chars
          (unless (nth 4 state)
            (parse-partial-sexp beg end nil nil state :commentstop)
            (setq beg (point))))))

    (if (and (natnump ffap-max-region-length)
             (< region-len ffap-max-region-length)) ; Bug#25243.
        (setf ffap-string-at-point-region (list beg end)
              ffap-string-at-point
              (buffer-substring-no-properties beg end))
      (setf ffap-string-at-point-region (list 1 1)
            ffap-string-at-point ""))))
(advice-add 'ffap-string-at-point :override #'modi/ffap-string-at-point)
Kaushal Modi
fuente
2

Creo que la piratería find-file-at-pointes fácil, se puede utilizar defadviceen find-file-at-point.

El punto clave es detectar si el cursor está en un comentario. Tuve un problema similar al desarrollar evil-nerd-commenter. Aquí está la función que puede reutilizar. El truco es detectar la fuente actual.

(defun evilnc--in-comment-p (pos)
  (interactive)
  (let ((fontfaces (get-text-property pos 'face)))
    (when (not (listp fontfaces))
      (setf fontfaces (list fontfaces)))
    (delq nil
      (mapcar #'(lambda (f)
              ;; learn this trick from flyspell
              (or (eq f 'font-lock-comment-face)
              (eq f 'font-lock-comment-delimiter-face)))
          fontfaces))))
Chen Bin
fuente
0

Sé que esto no se trata exactamente de lo que pidió el OP, pero una forma simple de hacer que ffap haga lo que quieres es darle un pequeño consejo.

(defun delp--ffap-string-at-point-filter (s)
  "Remove long stretches of /////'s from `ffap-string-at-point' return value."
  (interactive "sTest string: ")
  (if (string-match-p "^//" s)
      ""
    s))

(advice-add 'ffap-string-at-point :filter-return 'delp--ffap-string-at-point-filter)

Editar: se corrigió una cita lambda incorrecta (# '=> solo') Entiendo que los emacsen modernos prefieren '# pero los que no lo prefieren, no lo entiendo.

Para mí, esto funcionó. Realmente aprecié las ideas de Kaushal Modi, Sigma, Chen bin y Giles.

Uso cadenas extendidas de //// para dividir la página, y a menudo estoy en el encabezado cuando intento encontrar el directorio actual o un archivo en él. Sé que este consejo no servirá para todos; Lo puse aquí porque una búsqueda en ffap me trajo aquí. Otros pueden tener diferentes consejos personales para proporcionar la función. Según lo que leí aquí, escribí el código anterior.

He estado usando Emacs desde 1984, y algunas de las nuevas características no aparecen en mi radar hasta que veo algún código. Recomiendo la sección de información sobre consejos. O en emacs (Info-goto-node "(elisp)Advising Functions").

AncianoAyuda
fuente