Bagaimana cara menonaktifkan ffap (menemukan file di titik) ketika dua karakter non-spasi pertama dalam sebuah baris adalah '//'?

8

Di Verilog / C / C ++, komentar dapat dimulai dengan //.

Berikut ini contoh komentar, //This is a comment

Saya suka menggunakan fitur find-file-at-point . Jika kursor saya ada pada nama file di `include "some_file.v".

Tetapi jika kursor saya ada pada contoh komentar di atas dan jika saya menekan C-x C-f, emacs mencoba untuk membuka jalan tentatif //This!

Bagaimana cara saya selektif mencegah find-file-at-point aktif? Dalam hal ini, ketika mode utama adalah verilog-mode, bagaimana saya TIDAK lakukan find-file-at-pointketika kursor saya berada pada garis di mana 2 karakter non-spasi pertama berada //?

Kaushal Modi
sumber
Saya tidak begitu mengerti penggunaan kata sandi Anda ... Apakah Anda memetakan C-x C-fke ffapatau ke pembungkus ffap?
T. Verron
Periksa fungsi yang dipetakan untuk Anda C-x C-f(oleh C-h kRET C-x C-f). Seharusnya mengatakannya "menjalankan perintah" find-file.
caisah
Saya tidak dapat mereproduksi ini pada 24.3.1 GNU Emacs saya. Mungkin bug ini (seperti catatan @Sigma) telah dipecahkan?
remvee
2
@remvee find-file-at-pointFitur ini dinonaktifkan secara default. Saya telah mengaktifkannya via ido. Saya miliki (setq ido-use-filename-at-point 'guess)di konfigurasi saya.
Kaushal Modi

Jawaban:

9

Ini agak mengecewakan, karena ffap.elmemiliki beberapa kode yang harus melakukan hal itu:

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

Namun sayangnya, itu bergantung pada adanya ruang setelah pemisah komentar.

Ini juga sangat mengecewakan, karena penanda komentar tidak boleh menjadi bagian dari string-at-point. Jadi, inilah versi tambalan ffap-string-at-pointyang mencoba mengabaikan penanda itu secara sistematis

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

Efek samping itu memperbaiki masalah Anda, tetapi jauh lebih umum. Saya ingin tahu apakah perbaikan seperti itu harus diintegrasikan ke hulu.

Sigma
sumber
Menambahkan (require 'ffap). Saya menyadari bahwa tambalan ini tidak efektif dalam emacs init karena ffapmungkin akan dimuat secara otomatis .. yang tidak terjadi sebelum saya berinteraksi secara interaktiffind-file
Kaushal Modi
Saya akan menyambut perbaikan hulu.
wasamasa
2
@wasamasa Selesai: git.savannah.gnu.org/cgit/emacs.git/commit/…
Kaushal Modi
4

Berkat solusi yang diposting oleh @Sigma . Saya memiliki solusi itu di konfigurasi saya selama lebih dari 2 tahun, dan akhirnya mengirimkannya sebagai patch untuk emacs di hulu.

Komit dalam master emacs: e472cfe8


Inilah yang dilakukan patch secara efektif:

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

Saya pikir hack find-file-at-pointmudah, Anda dapat menggunakan defadvicedi find-file-at-point.

Poin kuncinya adalah mendeteksi apakah kursor dalam komentar. Saya memiliki masalah serupa ketika berkembang evil-nerd-commenter. Berikut adalah fungsi yang dapat Anda gunakan kembali. Caranya adalah mendeteksi wajah font saat ini.

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

Saya tahu bahwa ini bukan persis apa yang diminta OP, tetapi cara sederhana untuk mendapatkan apa yang Anda inginkan adalah dengan memberikan sedikit saran.

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

Sunting: memperbaiki kutipan lambda yang salah (# '=> just') Saya mengerti bahwa emacsen modern lebih memilih '# tetapi yang tidak menyukainya, tidak memahaminya.

Bagi saya, ini berhasil. Saya sangat menghargai wawasan Kaushal Modi, Sigma, Chen bin, dan Giles.

Saya menggunakan string //// yang diperluas untuk memecah halaman, dan saya sering berada di header ketika mencoba menemukan direktori saat ini atau file di dalamnya. Saya tahu bahwa nasihat ini tidak akan berlaku untuk semua; Saya taruh di sini karena pencarian di ffap membawa saya ke sini. Orang lain mungkin memiliki saran pribadi yang berbeda untuk menyediakan fungsi. Berdasarkan apa yang saya baca di sini, saya menulis kode di atas.

Saya telah menggunakan Emacs sejak 1984, dan beberapa fitur baru tidak masuk ke radar saya sampai saya melihat beberapa kode. Saya merekomendasikan bagian Info tentang saran. Atau di emacs (Info-goto-node "(elisp)Advising Functions").

ElderDelp
sumber