1
\$\begingroup\$

So I have a list of files which names are something like this

long_boring_filename_del_1.tex
long_boring_filename_del_2.tex
long_boring_filename_del_3.sty
long_boring_filename_del_4.tex

I want to cycle through these filenames using some mapping defined in vim. Meaning if I have long_boring_filename_del_2.tex open and hit the mapping it should take me to the next file long_boring_filename_del_3.sty. It should also loop, meaning long_boring_filename_del_4.tex should take me back to long_boring_filename_del_4.tex.

In addition I want to be able to cycle thorugh the files in both directions.

After obtaining a bit of help over at vi and vim I was able to come up with the following solution (which works).

function! s:next_del()

    " do nothing if current filename doesn't match "
    if @% !~# 'del-\v[1234]\.'
        return
    endif

    " open next file "
    let fnameA = substitute(@%, '\v[1234]\ze\.', '\=submatch(0)%4+1', '')
    if filereadable(fnameA)
        exec 'echo'
        exec 'e ' . fnameA
    else 
        " if the .tex file does not exist check if the .sty versions does "
        let fnameB = substitute(fnameA, '\.tex', '\.sty', '')
        if filereadable(fnameB)
            exec 'e ' . fnameB
        else 
            " if the above fails, check if changing sty to tex works "
            let fnameB = substitute(fnameA, '\.sty', '\.tex', '')
            if filereadable(fnameB)
                exec 'e ' . fnameB
            endif
        endif
    endif
endfunction

" Same as s:next_del() except this cycles in the opposite direction "
function! s:prev_del()

    " do nothing if current filename doesn't match "
    if @% !~# 'del-\v[1234]\.'
        return
    endif

    " open previous file "
    let fnameA = substitute(@%, '\v[1234]\ze\.', '\=submatch(0)-1', '')
    let fnameA = substitute(fnameA, '\v[0]\ze\.', '\=submatch(0)+4', '')
    if filereadable(fnameA)
        exec 'e ' . fnameA
    else 
        " if the .tex file does not exist check if the .sty versions does "
        let fnameB = substitute(fnameA, '\.tex', '\.sty', '')
        if filereadable(fnameB)
            exec 'e ' . fnameB
        else
            " if the above fails, check if changing sty to tex works "
            let fnameB = substitute(fnameA, '\.sty', '\.tex', '')
            if filereadable(fnameB)
                exec 'e ' . fnameB
            endif
        endif
    endif
endfunction

nnoremap <silent> <localleader>w :call <sid>next_del()<CR>
nnoremap <silent> <localleader>q :call <sid>prev_del()<CR>

While it work I would love to get some pointers on how to improve the code as I am very much a beginner when it come to vimscript. Here are the major points in the code that needs improvement:

  • Can the two functions s:next_del() and s:prev_del() be combined into one?
  • My method of cycling backwards is very barbaric.

    let fnameA = substitute(@%, '\v[1234]\ze\.', '\=submatch(0)-1', '')
    let fnameA = substitute(fnameA, '\v[0]\ze\.', '\=submatch(0)+4', '')
    

    I did it in this fashion because apparently you can't separate the leading \ and = , as otherwise it's a pure string. I would like to get some pointers on how to improve it.

  • Lastly my method of "checking" whether I have a sty file or tex file is strange at best. I do not really check, just change sty to tex and see if it works. I tried to get some regex going by using (tex|sty) but for some reason vimscript did not accept it. I would like to learn a better method of alternating between the sty and tex files.

\$\endgroup\$

Your Answer

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

Browse other questions tagged or ask your own question.