I'm not sure why RVM is still my default Ruby version manager yet the issue at hand should be reproducible on rbenv too.
Let's add a bit of context to this: we have an API written in Ruby and running on JRuby i.e. via JVM which implies slow start-up times compared to CRuby (yes, even with export JRUBY_OPTS='--dev'
). I use Vim 8.0.502 which of course comes by default bundled with Tim Pope's vim-ruby .
The problem: since I've switched to JRuby I started to notice a slowdown whilst working in Vim with .rb files. I did not pay too much attention to it at first (read almost for a month) but today it really started to bug me. I had no idea what was causing the slowdown so I tried Vim's trusty command-line option:
vim --startuptime profile-data app/controllers/application_controller.rb
which yielded (edited for brevity):
104.316 002.877 002.877: sourcing /usr/local/share/vim/vim80/syntax/ruby.vim 1228.691 1123.486 1123.486: sourcing /usr/local/share/vim/vim80/ftplugin/ruby.vim 1229.935 000.686 000.686: sourcing /usr/local/share/vim/vim80/indent/ruby.vim { edited } 1273.618 043.838: opening buffers 1274.471 000.853: BufEnter autocommands 1274.475 000.004: editing files in windows 1274.924 000.449: VimEnter autocommands 1274.932 000.008: before starting main loop 1299.500 024.568: first screen update 1299.501 000.001: --- VIM STARTED ---
Over one second to open a simple Ruby file? auch!
The relevant line in that file is:
1228.691 1123.486 1123.486: sourcing /usr/local/share/vim/vim80/ftplugin/ruby.vim
Why are we spending one second in ruby.vim
? the answer is in this function which gets executed before opening a .rb file:
function! s:query_path(root) abort let code = "print $:.join %q{,}" if &shell =~# 'sh' && empty(&shellxquote) let prefix = 'env PATH='.shellescape($PATH).' ' else let prefix = '' endif if &shellxquote == "'" let path_check = prefix.'ruby --disable-gems -e "' . code . '"' else let path_check = prefix."ruby --disable-gems -e '" . code . "'" endif
Note: ftplugin
stands for filetype and not FTP - so yes, this logic is required.
After all of this I did one more test: using top
in another tmux window I could actually see the Java process running after Vim therefore the issue was trivial: vim-ruby
was using JRuby.
The logical next step: instruct Vim to use CRuby if RVM with JRuby is detected. After some googling around the solution was an appendix to .vimrc
:
if !empty(matchstr($MY_RUBY_HOME, 'jruby')) let g:ruby_path = '/usr/bin/ruby' endif
Basically if RVM has set-up JRuby already instruct vim-ruby
via its helpful ruby_path
config to use the system's default Ruby (on macOS that being - CRuby version 2.0.0p648)
Results after the fix:
104.643 002.876 002.876: sourcing /usr/local/share/vim/vim80/syntax/ruby.vim 106.938 001.369 001.369: sourcing /usr/local/share/vim/vim80/ftplugin/ruby.vim 108.062 000.622 000.622: sourcing /usr/local/share/vim/vim80/indent/ruby.vim { edited } 152.700 044.957: opening buffers 153.389 000.689: BufEnter autocommands 153.394 000.005: editing files in windows 154.086 000.692: VimEnter autocommands 154.092 000.006: before starting main loop 178.172 024.080: first screen update 178.174 000.002: --- VIM STARTED ---
~200ms => much better.