0

I am wondering about a regex that would enable me to get the final "directory/file" from a path. I'll explain the reason why. After using vim for 20+ years, I've finally had cause to edit "over scp". To keep things simple between my remote systems and my local git clone, I edit the files remotely (because I have to build on the remote host), but I only commit/push from the local clone. I've written a simple function, WriteLocal(), which I've mapped to some simple keystrokes to pull the components I need to write the file into the local repo (working copy). The function now looks like this

function! WriteLocal()
   let ldir = matchstr(expand('%:h'), '\w\+$')
   let lfile = expand('%:t')
   execute 'w!' ldir . "/" . lfile
endfunction

I resorted to this because I just couldn't get a regex to work that would pull apart the "scp path" and give me just the final directory and file name. These are some of my attempts

let foo = matchstr(expand('%'), '\w\+/\{-}.\+$')
" or this one
let foo = matchstr(expand('%'), '\w\{-}/\{1}.\+$')

Neither of these worked as g:foo was empty. I do have a solution and though it works, if there is a way to make it concise to a single line, I'd like that solution. Perhaps a solution exists which doesn't use regex? I didn't even consider that until writing this. Does vimscript have a way to split a string into an array?

6
  • 3
    Why do it with a regex when expand/fnamemodify can do dirname/basename so easily?
    – D. Ben Knoble
    Oct 12 '20 at 22:20
  • @D.BenKnoble because I didn't know that fnamemodify existed. I've just tried it in some experiments and I likely don't understand it. It doesn't seem to work for me. Yesterday, I eventually settled on a solution using expand and findfile. This had the benefit of returning a path relative to pwd, which is what I wanted. Oct 13 '20 at 14:34
  • Perhaps you could clarify what you want. To get the dirname/basename of the current file, you need expand('%:h') and expand('%:t'). For a general string, fnamemodify(file, ':h'), fnamemodify(file, ':t'). For just the last directory, use :h:t. Does "path" in the title refer to the option 'path' or to a generic file-path?
    – D. Ben Knoble
    Oct 13 '20 at 14:44
  • You can also use :. to get paths relative to the current directory (if possible)
    – D. Ben Knoble
    Oct 13 '20 at 14:47
  • @D.BenKnoble That's a great question, about path in the title. I meant it as a general path because I am editing over scp. The directory path to the point of the git clone on the remote would be different than my local, but once in the clone, it's the same. Because I am editing code on a remote system that is in the same repo, I put my shell at the root. A path relative to that point was the goal. Thanks for the help. Learning how to script vim is great. Oct 13 '20 at 15:02
0

As recommended by @D.BenKnoble, I am posting an answer to my question. The problem to solve is saving a file to a local clone of a repo that is being edited remotely via scp. Except for the location of where the cloned repo is stored, the paths are identical once into the repository structure. So, considering this path scp://theremotehost//path/to/repo/src/file.cpp, the components which make up the local file are src/file.cpp. This assumes your vim/gvim session is started at the root of the repo clone.

At first I was trying to solve the problem using regex's. I happen to like them, but in this case, whether a limitation of vim's regex engine or my ignorance of vim's regex syntax, I was unable to find a solution using regex. However, the solution was simpler than using regex anyway. I settled on using a solution using expand() and findfile() which has the benefit of not restricting the returned path to a file but one dir deep in the structure:

function! WriteLocal()
    let foo = expand('%:t')
    let lfile = findfile(foo, '**')
    if lfile == ""
        echo cannot save the file, it does not exist
        return
    endif
    echo 'Saving file ' . lfile
    execute 'w!' lfile
endfunction
nmap ;wl :call WriteLocal()<cr>

This has the benefit that the target file may exist arbitrarily deep in the repo structure. If there are more clever solutions, please comment or post an answer.

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.