7

In Verilog/C/C++, comments can begin with //.

Here's an example comment, //This is a comment

I like to use the find-file-at-point feature. If my cursor is on the file name in `include "some_file.v".

But if my cursor is on the above example comment and if I hit C-x C-f, emacs tries to open a tentative path //This!

How do I selectively prevent find-file-at-point from activating? In this case, when the major mode is verilog-mode, how do I NOT do find-file-at-point when my cursor is on a line where the first 2 non-space characters are //?

4
  • I don't quite understand your usecase... Did you remap C-x C-f to ffap or to a wrapper around ffap? Commented Sep 24, 2014 at 5:18
  • Check the function mapped for your C-x C-f (by C-h k RET C-x C-f). It should say it "runs the command" find-file. Commented Sep 24, 2014 at 6:01
  • I can't reproduce this on my 24.3.1 GNU Emacs. Maybe this bug (as @Sigma notes) has already been solved? Commented Sep 24, 2014 at 7:44
  • 2
    @remvee The find-file-at-point feature is disabled by default. I have it enabled via ido. I have (setq ido-use-filename-at-point 'guess) in my config. Commented Sep 24, 2014 at 16:12

4 Answers 4

9

This is a bit disppointing, because ffap.el has some code that should do just that:

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

But unfortunately, it relies on there being a space after the comment separator.

It's also very disappointing, because comment markers should never be part of any string-at-point. So here's a patched version of ffap-string-at-point that tries to systematically ignore those markers

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

By side effect it fixes your problem, but it's much more general. I'm wondering if such a fix should be integrated upstream.

3
  • Added the (require 'ffap). I realized this patch wasn't being effective in emacs init as ffap probably gets autoloaded.. which doesn't happen until I interactively do find-file Commented Nov 3, 2014 at 14:36
  • I would welcome an upstream fix. Commented Nov 3, 2014 at 14:36
  • 2
    @wasamasa Done: git.savannah.gnu.org/cgit/emacs.git/commit/… Commented Mar 23, 2017 at 17:00
4

Thanks to the solution posted by @Sigma. I had that solution in my config for more than 2 years, and finally sent that as a patch to emacs upstream.

Commit in emacs master: e472cfe8


Here is what the patch effectively does:

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

I think hacking find-file-at-point is easy, you can use defadvice on find-file-at-point.

The key point is detecting whether the cursor is in a comment. I had a similar issue when developing evil-nerd-commenter. Here is the function you can re-use. The trick is to detect the current font face.

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

I know that this is not exactly addressing what the OP asked, but a simple way to get ffap to do what you want is to give it just a little advice.

(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 incorrect lambda quote (#' => just ') I understand that modern emacsen prefer '# but the ones that do not prefer it, don't understand it.

For me, this worked. I really appreciated the insights of Kaushal Modi, Sigma, Chen bin, and Giles.

I use extended strings of ////'s to break up the page, and I am often in the header when trying to find either the current directory or a file therein. I know that this advice will not serve for all; I put it here because a search on ffap brought me here. Others might have different personal advice to provide the function. Based on what I read here, I wrote the code above.

I have been using Emacs since 1984, and some of the new features do not get on my radar until I see some code. I recommend the Info section on advice. Or in emacs (Info-goto-node "(elisp)Advising Functions").

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.