Unity Development with Vim and Git in Windows – Part 2

View Part 1

Styling

Right now our setup looks terrible. Let’s do a few things to fix it up.

First we’ll add some colors. Color schemes are stored in the home directory/vimfiles/colors as .vim files. One of my favorites is the mustang color scheme. We’ll just create the colors directory, git clone the mustang color theme, then move the newly cloned .vim file to our colors directory. The URL for the scheme is https://github.com/croaker/mustang-vim.git

bash git mustang

Here I switch to the vimfiles directory, mkdir colors directory and clone the git repository that has the mustang.vim file that I’m after. Once I’ve cloned it, I do a few ls commands to see where it put the file, and once I find it, I use mv (move command) to move it into my colors directory, and verify it’s there.

Switching back to our Windows command prompt, type gvim _vimrc. We need to edit the _vimrc file to tell gVim to use this new color scheme with:

colorscheme mustang

While we’re here, let’s go ahead and set a few more options. I like the Liberation Mono font, and to remove the extra tool bars in gVim. (Just download the font like normal and double click to install it).vimrc styling

Save and quit, then open it back up and you should see this:

gvim mustang

I realized there’s an extra vertical scrollbar on the left of NERDTree. The :help command inside vim can be extremely helpful. I typed :help guioptions and in this case, I saw that I needed an additional command in my _vimrc file, so I added “set guioptions-=L” to fix the issue. The capital L removes scrollbars when multiple windows are open inside vim.

 

Status bar

Next thing we’ll add is a status bar to the bottom of vim. I think vim-airline does a great job, so let’s git clone that to our bundles directory. As a quick note, it’s usually helpful to always have a terminal and a command prompt open.

Back in our terminal, clone vim-airline into bundle/vim-airline. There are several ways we can do that. This time we’ll be explicit about the path we want to clone it to:

git clone https://github.com/bling/vim-airline ~/vimfiles/bundle/vim-airline

Now that it’s installed, so back into Vim (if it’s open, close it and reopen it in command prompt with gvim _vimrc, we use _vimrc since we’ll be making changes to it, but also to see the effects the plugins have) type “:Helptags” (make sure it’s capitalized) which will go through our plugins and generate the help files. :help <space> <what you want help with> is extremely useful to understand how to configure vim and plugins. To read about airline, just type “:help airline”. For our purposes, we’ll start with a basic configuration, so edit the _vimrc file and add “set laststatus=2”:

vimrc airline

:wq to save and quit, and once you reopen

airline

This will serve as a quick reference to see what mode we’re in, the file we’re on, the file type, and scroll/line/column stats.

OmniSharp + more plugins

OmniSharp is going to emulate some of the best features of Visual Studio for Vim like intellisense and code completion. First clone the git repository to bundle/omnisharp-vim. Then we’re going to use a git submodule command with is a repository within a repository. You wouldn’t necessary automatically “know” to use this command, because normally you wouldn’t have to. In this case, the installation instructions for OmniSharp specifically tell you to:

git clone https://github.com/OmniSharp/omnisharp-vim.git
cd omnisharp-vim
git submodule update --init --recursive

git omnisharp

For the next step, you’ll need to have Visual Studio installed and use it’s command prompt. The link will be under or Visual Studio menu folder under Tools called Developer Command Prompt for VS2013 (in my case using Visual Studio 2013). Whichever version to use, you can find the .bat file to run under your Visual Studio installation directory\Common7\Tools\VsDevCmd.bat. It should open a command prompt in your VS directory. cd to your Users\<your username\vimfiles\bundle\omnisharp-vim\server and run msbuild:

dev cmd prompt

That will build out several things for OmniSharp. After it’s done you can close out that prompt. Now we’ll need to install Python 2.7. There are two versions, x86 and x64. We want this to match our Vim version, which for Windows should be the 32 bit version (x86). At the time of this writing, the download is Windows x86 MSI Installer (2.7.8).

You can open up Vim again and type “:echo has(‘python’)” and you should see a “1” to verify that Python is working in Vim.

Now that the core part of OmniSharp is in, we’ll want to install a few other plugins that work alongside OmniSharp.

vim-dispatch: Used to automatically kicking off different processes. For OmniSharp it will automatically start the server which is used for code completion. Clone to your vimfiles/bundle (git clone git://github.com/tpope/vim-dispatch.git)
syntastic: Used for showing syntax errors in the code file. (git clone https://github.com/scrooloose/syntastic.git)
ctrlp: Used for keyboard shortcuts to quick open files, find types and symbols, etc. (git clone https://github.com/ctrlpvim/ctrlp.vim.git)

git more

Open up Vim again and add “let g:OmniSharp_selector_ui = ‘ctrlp’ in your _vimrc.

Basic OmniSharp

We’ve still got plenty of configurations to do, but let’s get a sample of how Vim will be working with OmniSharp. OmniSharp will look for a solution file (.sln) to enable code completion. We’ll want to start Vim from the directory in the Unity project with your scripts. So in your command prompt, cd into the scripts directory of a Unity Project. For example, I have a Scripts folder in my Unity project. So I’ll open up a command prompt, and “cd gamedev\UnityGame\Assets\Scripts”. From there just type gvim to open up a blank file. Type comma n “,n” to open up NERDTree, and open up a .cs file (select the file in NERDTree and hit ‘o’). If you have multiple .sln files (Unity sometimes creates multiple ones), select the one with the “-csharp” on the end. This will start up the OmniSharp server, press enter to confirm, and “,n” again to close NERDTree. To show the code completion hit ctrl-x ctrl-o. You can edit the file here like you normally would, and when you need to open another one, you can toggle NERDTree again, and hit o to open up the other file, or hit s to vertically split your screen. Or you can use ctrlp by keying ctrl-p then start typing the name of the file you want to open.

Enabling Autocomplete while typing

We’ll git clone a plugin called neocomplcache like everything else to our bundle directory:

git clone https://github.com/Shougo/neocomplcache.vim.git

The OmniSharp documentation has a preconfigured vimrc we can copy/paste into our _vimrc

let g:neocomplcache_enable_at_startup = 1
" Use smartcase.
let g:neocomplcache_enable_smart_case = 1
" Use camel case completion.
let g:neocomplcache_enable_camel_case_completion = 1
" Use underscore completion.
let g:neocomplcache_enable_underbar_completion = 1
" Sets minimum char length of syntax keyword.
let g:neocomplcache_min_syntax_length = 0
" buffer file name pattern that locks neocomplcache. e.g. ku.vim or fuzzyfinder 
"let g:neocomplcache_lock_buffer_name_pattern = '\*ku\*'

let g:neocomplcache_enable_auto_close_preview = 0
" Define keyword, for minor languages
if !exists('g:neocomplcache_keyword_patterns')
  let g:neocomplcache_keyword_patterns = {}
endif
let g:neocomplcache_keyword_patterns['default'] = '\h\w*'

" Plugin key-mappings.
inoremap <expr><C-g>     neocomplcache#undo_completion()
inoremap <expr><C-l>     neocomplcache#complete_common_string()

" SuperTab like snippets behavior.
"imap <expr><TAB> neocomplcache#sources#snippets_complete#expandable() ? "\<Plug>(neocomplcache_snippets_expand)" : pumvisible() ? "\<C-n>" : "\<TAB>"

" Recommended key-mappings.
" <CR>: close popup and save indent.
inoremap <expr><CR> pumvisible() ? neocomplcache#close_popup() : "\<CR>"
inoremap <expr>.  neocomplcache#close_popup() . "."
inoremap <expr>(  neocomplcache#close_popup() . "("
inoremap <expr>)  neocomplcache#close_popup() . ")"
inoremap <expr><space>  neocomplcache#close_popup() . " "
inoremap <expr>;  neocomplcache#close_popup() . ";"
" <TAB>: completion.
inoremap <expr><TAB>  pumvisible() ? "\<C-n>" : "\<TAB>"
" <C-h>, <BS>: close popup and delete backword char.
inoremap <expr><C-h> neocomplcache#smart_close_popup()."\<C-h>"
inoremap <expr><BS> neocomplcache#smart_close_popup()."\<C-h>"
inoremap <expr><C-y>  neocomplcache#close_popup()
inoremap <expr><C-e>  neocomplcache#cancel_popup()
inoremap <expr><ESC> pumvisible() ? neocomplcache#cancel_popup() : "\<esc>"

" AutoComplPop like behavior.
let g:neocomplcache_enable_auto_select = 1

" Shell like behavior(not recommended).
set completeopt+=longest
"let g:neocomplcache_disable_auto_complete = 1
"inoremap <expr><TAB>  pumvisible() ? "\<Down>" : "\<TAB>"
"inoremap <expr><CR>  neocomplcache#smart_close_popup() . "\<CR>"

" Enable heavy omni completion, which require computational power and may stall the vim. 
if !exists('g:neocomplcache_omni_patterns')
  let g:neocomplcache_omni_patterns = {}
endif
let g:neocomplcache_omni_patterns.ruby = '[^. *\t]\.\w*\|\h\w*::'
let g:neocomplcache_omni_patterns.cs = '.*'
"autocmd FileType ruby setlocal omnifunc=rubycomplete#Complete
let g:neocomplcache_omni_patterns.php = '[^. \t]->\h\w*\|\h\w*::'
let g:neocomplcache_omni_patterns.c = '\%(\.\|->\)\h\w*'

Configuring OmniSharp

We’ll also grab the example vimrc for the base OmniSharp configuration:

"This is the default value, setting it isn't actually necessary
let g:OmniSharp_host = "http://localhost:2000"

"Set the type lookup function to use the preview window instead of the status line
"let g:OmniSharp_typeLookupInPreview = 1

"Timeout in seconds to wait for a response from the server
let g:OmniSharp_timeout = 1

"Showmatch significantly slows down omnicomplete
"when the first match contains parentheses.
set noshowmatch

"Super tab settings - uncomment the next 4 lines
"let g:SuperTabDefaultCompletionType = 'context'
"let g:SuperTabContextDefaultCompletionType = "<c-x><c-o>"
"let g:SuperTabDefaultCompletionTypeDiscovery = ["&omnifunc:<c-x><c-o>","&completefunc:<c-x><c-n>"]
"let g:SuperTabClosePreviewOnPopupClose = 1

"don't autoselect first item in omnicomplete, show if only one item (for preview)
"remove preview if you don't want to see any documentation whatsoever.
set completeopt=longest,menuone,preview
" Fetch full documentation during omnicomplete requests.
" There is a performance penalty with this (especially on Mono)
" By default, only Type/Method signatures are fetched. Full documentation can still be fetched when
" you need it with the :OmniSharpDocumentation command.
" let g:omnicomplete_fetch_documentation=1

"Move the preview window (code documentation) to the bottom of the screen, so it doesn't move the code!
"You might also want to look at the echodoc plugin
set splitbelow

" Get Code Issues and syntax errors
let g:syntastic_cs_checkers = ['syntax', 'semantic', 'issues']
" If you are using the omnisharp-roslyn backend, use the following
" let g:syntastic_cs_checkers = ['code_checker']
augroup omnisharp_commands
    autocmd!

    "Set autocomplete function to OmniSharp (if not using YouCompleteMe completion plugin)
    autocmd FileType cs setlocal omnifunc=OmniSharp#Complete

    " Synchronous build (blocks Vim)
    "autocmd FileType cs nnoremap <F5> :wa!<cr>:OmniSharpBuild<cr>
    " Builds can also run asynchronously with vim-dispatch installed
    autocmd FileType cs nnoremap <leader>b :wa!<cr>:OmniSharpBuildAsync<cr>
    " automatic syntax check on events (TextChanged requires Vim 7.4)
    autocmd BufEnter,TextChanged,InsertLeave *.cs SyntasticCheck

    " Automatically add new cs files to the nearest project on save
    autocmd BufWritePost *.cs call OmniSharp#AddToProject()

    "show type information automatically when the cursor stops moving
    autocmd CursorHold *.cs call OmniSharp#TypeLookupWithoutDocumentation()

    "The following commands are contextual, based on the current cursor position.

    autocmd FileType cs nnoremap gd :OmniSharpGotoDefinition<cr>
    autocmd FileType cs nnoremap <leader>fi :OmniSharpFindImplementations<cr>
    autocmd FileType cs nnoremap <leader>ft :OmniSharpFindType<cr>
    autocmd FileType cs nnoremap <leader>fs :OmniSharpFindSymbol<cr>
    autocmd FileType cs nnoremap <leader>fu :OmniSharpFindUsages<cr>
    "finds members in the current buffer
    autocmd FileType cs nnoremap <leader>fm :OmniSharpFindMembers<cr>
    " cursor can be anywhere on the line containing an issue
    autocmd FileType cs nnoremap <leader>x  :OmniSharpFixIssue<cr>
    autocmd FileType cs nnoremap <leader>fx :OmniSharpFixUsings<cr>
    autocmd FileType cs nnoremap <leader>tt :OmniSharpTypeLookup<cr>
    autocmd FileType cs nnoremap <leader>dc :OmniSharpDocumentation<cr>
    "navigate up by method/property/field
    autocmd FileType cs nnoremap <C-K> :OmniSharpNavigateUp<cr>
    "navigate down by method/property/field
    autocmd FileType cs nnoremap <C-J> :OmniSharpNavigateDown<cr>

augroup END


" this setting controls how long to wait (in ms) before fetching type / symbol information.
set updatetime=500
" Remove 'Press Enter to continue' message when type information is longer than one line.
set cmdheight=2

" Contextual code actions (requires CtrlP or unite.vim)
nnoremap <leader><space> :OmniSharpGetCodeActions<cr>
" Run code actions with text selected in visual mode to extract method
vnoremap <leader><space> :call OmniSharp#GetCodeActions('visual')<cr>

" rename with dialog
nnoremap <leader>nm :OmniSharpRename<cr>
nnoremap <F2> :OmniSharpRename<cr>
" rename without dialog - with cursor on the symbol to rename... ':Rename newname'
command! -nargs=1 Rename :call OmniSharp#RenameTo("<args>")

" Force OmniSharp to reload the solution. Useful when switching branches etc.
nnoremap <leader>rl :OmniSharpReloadSolution<cr>
nnoremap <leader>cf :OmniSharpCodeFormat<cr>
" Load the current .cs file to the nearest project
nnoremap <leader>tp :OmniSharpAddToProject<cr>

" (Experimental - uses vim-dispatch or vimproc plugin) - Start the omnisharp server for the current solution
nnoremap <leader>ss :OmniSharpStartServer<cr>
nnoremap <leader>sp :OmniSharpStopServer<cr>

" Add syntax highlighting for types and interfaces
nnoremap <leader>th :OmniSharpHighlightTypes<cr>
"Don't ask to save when changing buffers (i.e. when jumping to a type definition)
set hidden

Configuring _vimrc

There’s another slew of settings we’ll add to the vimrc that will round out all our core customizations:

" Show relative line numbers
set rnu

" Map space key to center the view
:nmap <space> zz

" For highlighting trailing whitespaces
nnoremap <Leader>wn :match ExtraWhitespace /^\s* \s*\<Bar>\s\+$/<CR>
nnoremap <Leader>wf :match<CR>

set showmatch " Show matching braces when over one
set ruler " Always show current position
set number " Always show line-numbers
set numberwidth=5 " Line-number margin width
set mousehide " Do not show mouse while typing
set antialias " Pretty fonts
set t_Co=256 " 256-color palletes
set background=dark " Dark background variation of theme
" set guifont=Andale\ Mono\ 7.5 " Monospaced small font (Mike: Moved to bottom for custom)
set guioptions-=T " TODO
set guioptions+=c " TODO Console messages
set linespace=0 " Don't insert any extra pixel lines
set lazyredraw " Don't redraw while running macros
set wildmenu " Wild menu
set wildmode=longest,list,full " Wild menu options

" Tabbing, Default to 4 spaces as tabs
set cino=:0g0(0,W4
set expandtab
set tabstop=4
set softtabstop=4
set shiftwidth=4

" General behaviour
set autochdir " CWD is always same as current file
set ai " Autoident
"set si " Smartident
set nowrap " Do not wrap lines
set nocompatible " ViM settings instead of Vi
set smartcase " Smart casing when searching
set ignorecase " ... or ignore casing
set hlsearch " Highlight matches
set incsearch " Modern (wrapping) search
set history=500 " Long undo history
set tw=1000

" Ignore .meta files in NERDTree
let NERDTreeIgnore = ['\.meta$']

Okay, so that is a massive amount of customization. Look through it, use the :help to try to get a better idea of what it’s doing, and play around with it. In the next article I’ll go over the commands and workflows I use, as well as start integrating Git into Vim.