Skip to content

Working with older .csproj Projects

Nick Jensen edited this page Jan 22, 2020 · 7 revisions

Update: This functionality is now part of the vim-sharpenup plugin, which includes commands :SharpenUpAddToProject and :SharpenUpRenameInProject <newname>.


OmniSharp-vim does not have any notion of .csproj files, and OmniSharp-roslyn has no options for editing them. This means that adding a new file or renaming an existing one can break your project if you are using an older-style .csproj project, which lists all .cs files.

There is an open issue with OmniSharp-roslyn to alter the .csproj file, but it seems unlikely that this will be addressed, as the newer .csproj files don't need this functionality.

However, for OmniSharp-vim users stuck for the time being on older .csproj files, here are some functions which can be used to add and rename the current file in a .csproj. Please note that these are naiive and hacky functions, use at your own risk!

Put these functions in a ~/.vim/autoload/myomnisharp.vim script (create the ~/.vim/autoload directory if it doesn't already exist).

" ~/.vim/autoload/myomnisharp.vim

" Search from the current directory up to the solution directory for a .csproj
" file, and return the first one found. Note that this may return the wrong
" .csproj file if two .csproj files are found in the same directory.
function! s:FindProject() abort
  let l:base = fnamemodify(OmniSharp#FindSolutionOrDir(), ':h')
  let l:dir = expand('%:p:h')
  while 1
    let l:projects = split(globpath(l:dir, '*.csproj'), '\n')
    if len(l:projects)
      return l:projects[0]
    endif
    let l:parent = fnamemodify(l:dir, ':h')
    if l:dir ==# l:parent || l:dir ==# l:base
      echohl WarningMsg | echomsg 'Project not found' | echohl None
      return ''
    endif
    let l:dir = l:parent
  endwhile
endfunction

" Add the current file to the .csproj. The .csproj must be found in an ancestor
" directory and must already contain at least one .cs file.
function! myomnisharp#AddToProject() abort
  let l:filename = expand('%:p')
  let l:project = s:FindProject()
  if !len(l:project) | return | endif
  execute 'silent tabedit' l:project
  call cursor(1, 1)
  if !search('^\s*<compile include=".*\.cs"', '')
    tabclose
    echohl WarningMsg | echomsg 'Could not find a .cs entry' | echohl None
    return
  endif
  normal! yypk
  if fnamemodify(l:project, ':h') !=# getcwd()
    execute 'lcd' fnamemodify(l:project, ':h')
  endif
  execute 's/".*\.cs"/"' . fnamemodify(l:filename, ':.:gs?/?\\/?') . '"/'
  if g:OmniSharp_translate_cygwin_wsl || has('win32')
    s?/?\\?g
    s?\\>?/>?g
  endif
  write
  tabclose
endfunction

" Find the current file in the .csproj file and rename it to a:newname.
" Do not pass in a full path - just the new filename.cs
function! myomnisharp#RenameInProject(newname) abort
  let l:filepath = expand('%:p')
  let l:filename = expand('%:t')
  let l:project = s:FindProject()
  if !len(l:project) | return | endif
  execute 'silent tabedit' l:project
  call cursor(1, 1)
  if fnamemodify(l:project, ':h') !=# getcwd()
    execute 'lcd' fnamemodify(l:project, ':h')
  endif
  let l:filepath = fnamemodify(l:filepath, ':.')
  if g:OmniSharp_translate_cygwin_wsl || has('win32')
    let l:filepath = substitute(l:filepath, '/', '\\\\', 'g')
  endif
  " Search for the full file path, relative to the .csproj
  if !search(l:filepath, '')
    " If not found, try just the file name (without the path)
    if !search(fnamemodify(l:filepath, ':t'), '')
      tabclose
      echohl WarningMsg | echomsg 'Could not find ' . l:filepath | echohl None
      return
    endif
  endif
  execute 's/' . fnamemodify(l:filename, ':t') . '/' . a:newname . '/'
  write
  tabclose
endfunction

These mappings should be in a ~/.vim/after/ftplugin/cs.vim script, or in ~/.vimrcinautocmd FileType cs ...` autocommands like the ones in the suggested .vimrc in the README:

" ~/.vim/after/ftplugin/cs.vim

nnoremap <buffer> <Leader>add :call myomnisharp#AddToProject()<CR>
nnoremap <buffer> <Leader>ren :call myomnisharp#RenameInProject()<Left>