3

In part of a plugin I'm slowly building, I use <cfile> to get the file pointed by the word under the cursor and then do something if it points to a directory, or open the file pointed to otherwise (so unless the word under the cursors points to a directory, it's supposed to behave exactly like gf). It all works fine, except for suffixes.

help <cfile> in vim says:

<cfile> is replaced with the path name under the cursor (like what gf uses)

but while gf will include a possibly auto-detected suffix, this doesn't seem to be the case in <cfile>. Is there some kind of workaround for this?

In case it helps clarify my question, here's the relevant code excerpt:

  1 function! now#BufEnter() "{{{                                          
  2 " behaviour of <enter> while on now files (mapped on ftplugin)         
  3   execute "silent! normal! :set suffixesadd=" . g:NOW_suffix . "\r"    
  4   let l:dest = expand("<cfile>")                                       
  5   if isdirectory(l:dest)                                               
  6     " if pointing to a directory, update and enter index file there    
  7     execute 'normal! :cd ' . l:dest . "\r"                             
  8     call now#MakeIndex()                                               
  9   else                                                                 
 10     " otherwise edit the file, whether it exists or not                
 11     execute 'normal! :e ' . l:dest . "\r"                              
 12   endif                                                                
 13 endfunction "}}}

Line 3 was added for debugging purposes only, copied from elsewhere. The added suffix is flawlessly detected by gf, but not with the keymap pointing towards the above function (as the comments in the code mention, it is the <enter> key). When no suffix is needed, the code works as expected: do the directory stuff if need, or edit the pointed file, creating it if necessary.

  • 3
    What happens if you replace line 11 with just :normal! gf ? – VanLaser Sep 21 '16 at 22:07
  • @VanLaser : With just normal! gf regular gf is called and suffixes are indeed respected but if the file does not exist, it is not created (as per comment in line 10). Note that I don't expect a non-existing file to be created with a "guessed" suffix, but I do expect an existing file to be opened if there is one, seeking it with the environment suffixes. Maybe it is these two behaviours (lookup with suffix / create if not existing) that are actually incompatible with each other? – Dalker Sep 22 '16 at 5:38
  • 1
    In any case, thanks for the suggestion, @VanLaser. I'm going to use that variant for now, sacrificing the "create file if it doesn't exist" in favour of "follow the link with an optional implicit suffix if a possible file does exist". Actually, I could add another if to act differently if the file does not exist, and then: problem solved. Nevertheless, the help on <cfile> is a bit confusing (as <cfile> is clearly not quite like what gf uses) – Dalker Sep 22 '16 at 7:10
  • You're welcome :) Good to see you found a solution! – VanLaser Sep 22 '16 at 9:06
2

Prompted by the comment fron @VanLaser, I thought it may be possible to somehow discriminate the behaviour with an if filereadable() to decide whether invoking a regular gf or an :edit in order to work around the limitations of <cfile>. However, there's a catch: I don't know which file to seek for readability before invoking gf. So finally, after trying a bit, here's a solution... with a catch.

 1 function! now#BufEnter() "{{{
 2 " behaviour of <enter> while on now files (mapped on ftplugin)
 3   execute "silent! normal! :set suffixesadd=" . g:NOW_suffix . "\r"
 4   let l:dest = expand("<cfile>")
 5   if isdirectory(l:dest)
 6     " if pointing to a directory, update and enter index file there
 7     execute 'normal! :cd ' . l:dest . "\r"
 8     call now#MakeIndex()
 9   else
10     " otherwise edit the file, whether it exists or not
11     " N.B: this is a bit tricky, because <cfile> does not detect an optional
12     " suffix, as discussed in the following Q/A topic:
13     " https://vi.stackexchange.com/q/9627/2058
14     try
15       " if a file can be found, with optional suffix, open it
16       normal gf
17     catch
18       " otherwise, create the file pointed to
19       execute 'normal! :e ' . l:dest . "\r"
20     endtry
21   endif
22 endfunction "}}}

A nice side-effect of this is being able to actually add a specific suffix upon creation (not shown in above code, which, for reference, is only trying to modify the question's code enough to answer the actual question).

  • Nice! I wonder if you could use :find <file> instead of gf. Also I'm not sure you need the execute 'normal! :e ... construct on line 19 (why not directly execute 'e ...?) It's cool to see the URL of this question in the answer, it gives it an air of self-referencing :) (you may want to use the short form, for aesthetic reasons (?): vi.stackexchange.com/q/9627/1800) – VanLaser Sep 22 '16 at 9:22
  • Oh, I didn't realize there were shortened URLs available. Thanks for the tip @VanLaser. Just edited accordingly. As for the execute 'normal! ... construct, I use it very often since learning about it in LearnVimscripTheHardWay. It is particularly safe against a lot of annoyances. In this case, after testing now, with a direct execute 'e ... I get an extraneous ^M added to the filename, which is not the case with execute 'normal! – Dalker Sep 22 '16 at 12:01
  • As for :find, I don't think it would make things any simpler than "can gf open something? if yes, do it, if no, then create the most reasonable alternative". – Dalker Sep 22 '16 at 12:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.