5

I am editing a file which lives in a directory that is a symlink to another directory, i.e.

% ls -alh ~/www/experiments 
total 0
drwxr-xr-x 3 ubuntu ubuntu  80 Dec  5 19:52 .
drwxr-xr-x 3 ubuntu ubuntu  60 Dec  8 16:25 ..
lrwxrwxrwx 1 ubuntu ubuntu   8 Dec  5 19:52 tmp -> /tmp/web

so when I am editing the file:

~/www/experiments/tmp/webpage.php

Because the parent folder of webpage.php ( tmp ) is pointing to /tmp/web when I run the vimscript command

echo expand('%:p')

vim will echo the real file path, i.e.

/tmp/web/webpage.php

how can I make vim expand the symlinked path in vimscript? i.e. the desired output would be:

/home/ubuntu/www/experiments/tmp/webpage.php    

I've looked in :h filename-modifiers and there doesn't seem to be anything about symlinks. Also looked at functions like resolve() - unfortunately I think resolve() does the opposite of what I want, it produces the real file path.

  • I don't there there's an easy way to do this; getcwd()and :pwd also always return the full path, rather than the symlinked path that the shell's pwd command or $PWD variable use (In other words, it looks like Vim normalises the path on open). – Martin Tournoij Dec 10 '16 at 2:01
  • @Carpetsmoker yes, and also linux doesn't allow hardlinking to directories - which might have been able to "fool" vim. I think I have a work around though, I'm just using the match() function and an if block to detect when the filepath expands to the /tmp location, and if so, then substitute() to "fix" the path – the_velour_fog Dec 10 '16 at 2:05
  • I don't know what your goal is, but you can mount an NFS directory on the localhost to work around the inability to hardlink directories. On Linux you can also use mount --bind /src/ /dest, and on FreeBSD mount_nullfs /src /dest. Other systems may have similar constructs (e.g. directory junctions in Windows). Also see: What is a bind mount? at Unix.SE. – Martin Tournoij Dec 10 '16 at 2:07
  • @Carpetsmoker thanks for the info, mount --bind definitely looks interesting. I see what is a bind mount is one of Gilles' canonical answers. It usually takes me a day or two to get through those! I have finally got this working now anyway. The overall goal is that - when I am working on a webpage code file, and I want to view that files output in a browser, I simply hit a <Leader> mapping and vim launches a new browser tab with the corresponding URL for the file. – the_velour_fog Dec 10 '16 at 2:21
0

Check if a path has a symlink anywhere in it, and if so return 1, otherwise 0

Pseudocode: Use the shell to convert the symlink path to the path it points to. If the two paths are identical then it's not a symlink. Otherwise it is.

function! IsPathSymlinkPath(foo)
    "Sorry for the incantations.  Level 9 hax required.
    if ( substitute( 
        \ system('readlink -f ' . 
        \ a:foo), '^\s*\(.\{-}\)\_s*$', '\1', '') == 
        \ substitute(a:foo, '^\s*\(.\{-}\)\s*$', '\1', '') 
        \ )
        return 1
    endif
endfunction

echo IsPathSymlinkPath("/home/el/symlink/somefile")
"returns 1

echo IsPathSymlinkPath("/home/el/normal/somefile")
"returns 0

Or you could do it using vimscript's resolve and expand code

function! IsSymlinkPath(mypath)
    let resolved_expanded = resolve(expand(a:mypath))
    let trim_and_flatten_path = substitute(
        \ resolved_expanded, '^\s*\(.\{-}\)\s*$', '\1', '')
    let trim_original_mypath  = substitute(
        \ a:mypath, '^\s*\(.\{-}\)\s*$', '\1', '') 
    if ( trim_and_flatten_path == trim_original_mypath )
        return 1
    endif
endfunction

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.