0

My vimrc file is hosted on github. I update it once in a while, and use it on many different computers.

Is it possible to make vim asynchronously check the github repo for a new version of the vimrc file at startup?

I've seen something similar being done by the coc plugin, where on startup, it checks for updates, and if there is one, vim asks you if you want to download it. This isn't exactly the same, as it's checking for an update to a plugin, as opposed to a vimrc config file, but the idea seems similar.

The async part is so that it doesn't slow down vim startup time every single time, and it doesn't lock up vim if the system has no internet.

If it matters, I'm using neovim.

4
  • Assuming git pull is enough, this is totally doable, but you won’t see the updates take effect until you restart vim.
    – D. Ben Knoble
    Mar 27, 2021 at 22:43
  • I was thinking more of a GET request to the raw vimrc file on github. Maybe run a checksum on it, and compare it to a checksum of the current user's ~/.vimrc. Something like that. I'm fine with it not taking effect until a restart of vim (if there's not easy way to apply it immediately), as long as it tells me it updated, and that I should restart vim.
    – John
    Mar 28, 2021 at 23:44
  • 1
    Since your vimrc is in a git repo why not make use of git instead of re-implementing the feature? If you try to make the get request by yourself you'll need to recreate something portable and efficient vs. adding a simple :h system() call in your vimrc which will do a git pull in the repo holding your vimrc. If you don't want to do a pull automatically you can still do a git remote update to get the remote updated refs and then check if git status -uno shows a change. If there is a change then you display a message to pull.
    – statox
    Mar 29, 2021 at 8:52
  • @statox makes sense. Git already does checksums, and doesn't send the file over unless it's changed, unlike my GET request idea, which will send the file over every time. Git also does compression. All that's left is to actually make it work. I was hoping someone already had this working. If not, I'll give it a try when I have the time
    – John
    Mar 29, 2021 at 14:17

3 Answers 3

1

Here's a simple version, assuming fugitive or dispatch are installed:

augroup update_vimrc
  autocmd!
  " for dispatch, automatically async
  " use a ! or other dispatch commands for more control
  autocmd VimEnter Dispatch git -C ~/dotfiles pull
  " or for fugitive, not so async
  autocmd VimEnter Git -C ~/dotfiles pull
augroup END

If those are overkill for you, you can hack something together with system/systemlist()/:help job?

0

Since you use Neovim and you are fine with a simple message telling you to pull your dotfiles repository here is a very basic solution which you could work on.

The solution has its drawbacks (which I'll explain later) but it has the advantages of not relying on a plugin or any other tool than the git cli and of begin asynchronous, which I believe is important: Since you will call git remote update and that can take some time to execute you probably don't want to block neovim's UI will it runs.

So you can add that to your vimrc/init.vim:

" Asynchronously check if the dotfil repository has changes to pull
function CheckVimrcRemoteUpdate()
    " Put the dotfiles repo in a variable
    let dotfiles_repo_path = "$HOME/.dotfiles"
    " The shell command we will use to check for updates
    let cmd = 'cd ' . dotfiles_repo_path . ' && git remote update && git status -uno'

    " The function we will call when the git command as finished to be read
    function HandleData(chanid, data, name)
        " a:data holds all the lines of stdout
        " if the output contains the string 'is behind' then we show a message
        let is_behind = v:false
        for line in a:data
            if line =~ 'is behind'
                let is_behind = v:true
            endif
        endfor

        if (is_behind)
            echom 'Dotfiles should be updated'
        endif
    endfunction

    " Start an asynchronous job to execute the git command and execute HandleData on stdout
    call jobstart(cmd, {'stdout_buffered': v:true, 'on_stdout': function('HandleData')})
endfunction

" Run the CheckVimrcRemoteUpdate function after Vim start up
augroup CheckDotfiles
    autocmd!
    autocmd VimEnter * call CheckVimrcRemoteUpdate()
augroup END

The idea is to create a CheckVimrcRemoteUpdate() function which will do 3 things:

  • Build the command to be run by the script to check the status of your dotfile repository
  • Create a function which will handle the output of this command and display a message if you need to update your repo
  • Start a job which will run the command and attach the function to its result.

A few things to note:

  • The command ran is cd $your_repo_path && git remote update && git status -uno: This means that if you have a change in your repository which isn't about your vimrc file you will still get the message. You can probably play with git to have a better command checking only the status of this file (but you also probably want to check if the .vim directory has been updated too).
  • The check relies on git showing a line like Your branch is behind 'origin/master' by 47 commits this is not a very strict check and could probably be improved. As Ben suggested in the comments a first step to improve that is to force the local when running the command to avoid having the string localized if your system is not in English.
  • To show the notification I used echom, maybe you'll want a different UI.
  • 'stdout_buffered': v:true in the jobstart function is important to trigger HandleData only once you received all of the lines from stdout.
  • There is no error handling, so if you specify a directory which is not a git repo in dotfiles_repo_path things will most likely break. Same if you don't have network connectivity.
  • I put the call to CheckVimrcRemoteUpdate() in the VimEnter autocommand event, maybe there is a better one.

Relevant help topics:


FWIW a synchronous version of the solution would be this simple function:

" Synchronously check if the dotfiles repository has changes to pull
function CheckVimrcRemoteUpdate()
    " Put the dotfiles repo in a variable
    " let dotfiles_repo_path = "$HOME/.dotfiles"
    let dotfiles_repo_path = "$HOME/projects/nodews"
    " The shell command we will use to check for updates
    let data = systemlist('cd ' . dotfiles_repo_path . ' && git remote update && git status -uno')

    let is_behind = v:false
    for line in data
        if line =~ 'is behind'
            echom 'Dotfiles should be updated'
        endif
    endfor
endfunction
2
  • 1
    Might want to force the locale to avoid is behind not showing in translated output
    – D. Ben Knoble
    Mar 29, 2021 at 15:51
  • That would definitely be a good first improvement indeed.
    – statox
    Mar 29, 2021 at 15:54
0

The hard way is to use your dotfiles like a plugin:

Plug 'myrepo/vim-config'

then autocmd VimEnter to sync plugin when vim opened ,like:

" update all plugins
autocmd VimEnter * PlugUpdate
" or update your plugin by specefin you name
autocmd VimEnter * PlugUpdate [name ...]
" ! for force update
autocmd VimEnter * PlugUpdate! [name ...]

To use this option smoothly, you can build your repo somewhere outside the vim directories.

1
  • I change it to be VimEnter
    – nextloop
    Aug 28, 2021 at 22:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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