Como desabilito o ffap (localizar arquivo no ponto) quando os dois primeiros caracteres não espaciais de uma linha são '//'?

8

No Verilog / C / C ++, os comentários podem começar //.

Aqui está um exemplo de comentário, //This is a comment

Eu gosto de usar o recurso localizar arquivo no ponto . Se o meu cursor estiver no nome do arquivo em `include "some_file.v".

Mas se meu cursor estiver no comentário do exemplo acima e se eu clicar C-x C-f, o emacs tenta abrir um caminho experimental //This!

Como faço para impedir seletivamente a ativação de localizar arquivo no ponto ? Nesse caso, quando o modo principal está verilog-mode, como NÃO o faço find-file-at-pointquando meu cursor está em uma linha onde estão os 2 primeiros caracteres não espaciais //?

Kaushal Modi
fonte
Eu não entendo direito o seu caso ... Você remapou C-x C-fpara ffapou para um invólucro ffap?
T. Verron
Verifique a função mapeada para o seu C-x C-f(por C-h kRET C-x C-f). Deveria dizer que "executa o comando" find-file.
caisah 24/09/14
Não consigo reproduzir isso no meu 24.3.1 GNU Emacs. Talvez esse bug (como observa o @Sigma) já tenha sido resolvido?
Remvee
2
@remvee O find-file-at-pointrecurso está desativado por padrão. Eu o habilitei via ido. Eu tenho (setq ido-use-filename-at-point 'guess)na minha configuração.
Kaushal Modi

Respostas:

9

Isso é um pouco desapontador, porque ffap.eltem algum código que deve fazer exatamente isso:

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

Mas, infelizmente, depende de haver um espaço após o separador de comentários.

Também é muito decepcionante, porque os marcadores de comentários nunca devem fazer parte de qualquer string no momento. Então, aqui está uma versão corrigida ffap-string-at-pointque tenta ignorar sistematicamente esses 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 efeito colateral, ele corrige seu problema, mas é muito mais geral. Gostaria de saber se essa correção deve ser integrada a montante.

Sigma
fonte
Adicionado o (require 'ffap). Eu percebi este patch não estava sendo eficaz no emacs de init como ffapprovavelmente fica autoloaded .. o que não acontece até que eu interativamente fazerfind-file
Kaushal Modi
Gostaria de receber uma correção a montante.
wasamasa
2
@wasamasa Feito: git.savannah.gnu.org/cgit/emacs.git/commit/…
Kaushal Modi
4

Graças à solução postada pela @Sigma . Eu tive essa solução na minha configuração por mais de 2 anos e finalmente a enviei como um patch para o emacs upstream.

Confirmar no emacs master: e472cfe8


Aqui está o que o patch efetivamente faz:

(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
fonte
2

Eu acho que hackers find-file-at-pointé fácil, você pode usar defadviceon find-file-at-point.

O ponto principal é detectar se o cursor está em um comentário. Eu tive um problema semelhante ao desenvolver evil-nerd-commenter. Aqui está a função que você pode reutilizar. O truque é detectar a face da fonte atual.

(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
fonte
0

Eu sei que isso não é exatamente o que o OP pediu, mas uma maneira simples de obter o ffap para fazer o que você quer é dar apenas um pequeno conselho.

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

Edit: Fixed incorreta lambda quote (# '=> just') Eu entendo que o emacsen moderno prefere '# mas os que não o preferem, não o entendem.

Para mim, isso funcionou. Eu realmente apreciei as idéias de Kaushal Modi, Sigma, Chen bin e Giles.

Eu uso seqüências de caracteres estendidas de //// para quebrar a página, e geralmente estou no cabeçalho ao tentar encontrar o diretório atual ou um arquivo nele. Eu sei que esse conselho não servirá para todos; Coloquei aqui porque uma pesquisa no ffap me trouxe aqui. Outros podem ter conselhos pessoais diferentes para fornecer a função. Com base no que li aqui, escrevi o código acima.

Uso o Emacs desde 1984, e alguns dos novos recursos não ficam no meu radar até que eu veja algum código. Eu recomendo a seção Informações sobre conselhos. Ou no emacs (Info-goto-node "(elisp)Advising Functions").

ElderDelp
fonte