├── .gitattributes ├── .github └── workflows │ ├── tox.yml │ ├── vader.yml │ └── vint.yml ├── .gitignore ├── .gitmodules ├── LICENSE.md ├── README.md ├── ale_linters └── cs │ └── omnisharp.vim ├── autoload ├── OmniSharp.vim ├── OmniSharp │ ├── actions │ │ ├── buffer.vim │ │ ├── codeactions.vim │ │ ├── codestructure.vim │ │ ├── complete.vim │ │ ├── definition.vim │ │ ├── diagnostics.vim │ │ ├── documentation.vim │ │ ├── format.vim │ │ ├── highlight.vim │ │ ├── highlight_types.vim │ │ ├── implementations.vim │ │ ├── members.vim │ │ ├── navigate.vim │ │ ├── project.vim │ │ ├── rename.vim │ │ ├── signature.vim │ │ ├── symbols.vim │ │ ├── test.vim │ │ ├── typedefinition.vim │ │ ├── usages.vim │ │ ├── usings.vim │ │ └── workspace.vim │ ├── buffer.vim │ ├── locations.vim │ ├── log.vim │ ├── popup.vim │ ├── preview.vim │ ├── proc.vim │ ├── project.vim │ ├── py.vim │ ├── stdio.vim │ └── util.vim ├── ale │ └── sources │ │ └── OmniSharp.vim ├── asyncomplete │ └── sources │ │ └── OmniSharp.vim ├── clap │ └── OmniSharp.vim ├── coc │ └── source │ │ └── OmniSharp.vim ├── ctrlp │ └── OmniSharp │ │ ├── findcodeactions.vim │ │ └── findsymbols.vim ├── deoplete │ └── source │ │ └── omnisharp.vim ├── fzf │ └── OmniSharp.vim ├── ncm2 │ └── sources │ │ └── OmniSharp.vim └── unite │ └── sources │ └── OmniSharp.vim ├── doc └── omnisharp-vim.txt ├── ftdetect ├── cake.vim ├── csx.vim └── omnisharplog.vim ├── ftplugin ├── cs │ └── OmniSharp.vim └── omnisharplog │ └── OmniSharp.vim ├── installer ├── README.md ├── omnisharp-manager.ps1 └── omnisharp-manager.sh ├── log └── .placeholder ├── plugin └── OmniSharp.vim ├── python ├── .gitignore ├── .pylintrc ├── .python-version ├── README.md ├── ale_lint.py ├── bootstrap.py ├── omnisharp │ ├── __init__.py │ ├── commands.py │ ├── exceptions.py │ ├── util.py │ └── vimcmd.py ├── pyenv-bootstrap.sh ├── setup.cfg ├── setup.py ├── tests │ ├── __init__.py │ └── test_util.py └── tox.ini ├── rplugin └── python3 │ └── deoplete │ └── sources │ └── deoplete_OmniSharp.py ├── syntax ├── omnisharpdoc.vim └── omnisharplog.vim ├── syntax_checkers └── cs │ └── codecheck.vim └── test ├── README.md ├── codeformat.vader ├── complete.vader ├── example ├── .gitignore ├── Program.cs ├── example.csproj ├── example.sln └── omnisharp.json ├── fixusings.vader ├── gotodefinition.vader ├── gotometadata.vader ├── rename.vader ├── run-async.vader ├── utils ├── async-helper.vader └── startserver.vader └── vimrc /.gitattributes: -------------------------------------------------------------------------------- 1 | *.vim text eol=lf 2 | *.py text eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/tox.yml: -------------------------------------------------------------------------------- 1 | name: tox 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [windows-latest, ubuntu-latest, macos-latest] 16 | python-version: [3.9] 17 | 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@main 21 | 22 | - name: Setup Python 23 | uses: actions/setup-python@main 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | 27 | - name: Install Dependencies 28 | run: | 29 | pip install tox 30 | 31 | - name: Run Test 32 | run: | 33 | cd python 34 | tox -e py 35 | -------------------------------------------------------------------------------- /.github/workflows/vader.yml: -------------------------------------------------------------------------------- 1 | name: Vader 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | cfg: 16 | - { editor: vim, neovim: false, version: nightly } 17 | - { editor: vim, neovim: false, version: stable } 18 | - { editor: neovim, neovim: true, version: stable } 19 | 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@main 23 | 24 | - name: Setup dotnet 6.0 25 | uses: actions/setup-dotnet@main 26 | with: 27 | dotnet-version: '6.0' 28 | 29 | - name: Setup Vim 30 | uses: rhysd/action-setup-vim@v1 31 | with: 32 | neovim: ${{ matrix.cfg.neovim }} 33 | version: ${{ matrix.cfg.version }} 34 | 35 | - name: Install Dependencies 36 | run: | 37 | installer/omnisharp-manager.sh -6 -l $HOME/.omnisharp/omnisharp-roslyn 38 | git clone https://github.com/junegunn/vader.vim.git $GITHUB_WORKSPACE/../vader.vim 39 | 40 | - name: Run Test 41 | run: | 42 | cd test 43 | vim -esNu vimrc -c 'Vader! *' 44 | if: matrix.cfg.editor == 'vim' 45 | 46 | - name: Run Test 47 | run: | 48 | cd test 49 | nvim --headless -Nu vimrc -c 'Vader! *' 50 | env: 51 | VADER_OUTPUT_FILE: /dev/stderr 52 | if: matrix.cfg.editor == 'neovim' 53 | -------------------------------------------------------------------------------- /.github/workflows/vint.yml: -------------------------------------------------------------------------------- 1 | name: Vint 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | vint: 11 | name: runner / vint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: vint 16 | uses: reviewdog/action-vint@v1 17 | with: 18 | github_token: ${{ secrets.github_token }} 19 | level: error 20 | reporter: github-pr-review 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | *.orig 3 | **/tags 4 | ## Ignore Visual Studio temporary files, build results, and 5 | ## files generated by popular Visual Studio add-ons. 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.sln.docstates 11 | *.sublime-workspace 12 | 13 | # Build results 14 | 15 | [Dd]ebug*/ 16 | [Rr]elease/ 17 | 18 | #build/ 19 | 20 | 21 | [Tt]est[Rr]esult 22 | [Bb]uild[Ll]og.* 23 | 24 | *.pyc 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.vspscc 41 | *.vssscc 42 | .builds 43 | .DS_Store 44 | 45 | *.pidb 46 | 47 | *.log 48 | *.scc 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | 56 | # Visual Studio profiler 57 | *.psess 58 | *.vsp 59 | 60 | # Guidance Automation Toolkit 61 | *.gpState 62 | 63 | # ReSharper is a .NET coding add-in 64 | _ReSharper*/ 65 | 66 | *.[Rr]e[Ss]harper 67 | 68 | # NCrunch 69 | *.ncrunch* 70 | .*crunch*.local.xml 71 | 72 | # Installshield output folder 73 | [Ee]xpress 74 | 75 | # DocProject is a documentation generator add-in 76 | DocProject/buildhelp/ 77 | DocProject/Help/*.HxT 78 | DocProject/Help/*.HxC 79 | DocProject/Help/*.hhc 80 | DocProject/Help/*.hhk 81 | DocProject/Help/*.hhp 82 | DocProject/Help/Html2 83 | DocProject/Help/html 84 | 85 | # Click-Once directory 86 | publish 87 | 88 | # Publish Web Output 89 | *.Publish.xml 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | 103 | *.[Pp]ublish.xml 104 | 105 | Generated_Code #added for RIA/Silverlight projects 106 | 107 | # Backup & report files from converting an old project file to a newer 108 | # Visual Studio version. Backup files are not needed, because we have git ;-) 109 | _UpgradeReport_Files/ 110 | Backup*/ 111 | UpgradeLog*.XML 112 | 113 | # NuGet 114 | packages/ 115 | 116 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OmniSharp/omnisharp-vim/cdbf65bc4385d7026428d2f392b40a317725cc9c/.gitmodules -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 OmniSharp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ale_linters/cs/omnisharp.vim: -------------------------------------------------------------------------------- 1 | if !get(g:, 'OmniSharp_loaded', 0) | finish | endif 2 | if !OmniSharp#util#CheckCapabilities() | finish | endif 3 | " When using async/stdio, a different method is used, see 4 | " autoload/ale/sources/OmniSharp.vim 5 | if g:OmniSharp_server_stdio | finish | endif 6 | 7 | let s:delimiter = '@@@' 8 | 9 | function! ale_linters#cs#omnisharp#ProcessOutput(buffer, lines) abort 10 | let list = [] 11 | for line in a:lines 12 | let [filename, lnum, col, type, subtype, text] = split(line, s:delimiter, 1) 13 | let item = { 14 | \ 'filename': filename, 15 | \ 'lnum': lnum, 16 | \ 'col': col, 17 | \ 'type': type, 18 | \ 'text': text, 19 | \} 20 | if subtype ==? 'style' 21 | let item['sub_type'] = 'style' 22 | endif 23 | call add(list, item) 24 | endfor 25 | return list 26 | endfunction 27 | 28 | function! ale_linters#cs#omnisharp#GetCommand(bufnum) abort 29 | let linter = OmniSharp#util#PathJoin(['python', 'ale_lint.py']) 30 | let host = OmniSharp#GetHost(a:bufnum) 31 | let cmd = printf( 32 | \ '%%e %s --filename %%s --host %s --level %s --cwd %s --delimiter %s --encoding %s', 33 | \ ale#Escape(linter), ale#Escape(host), ale#Escape(g:OmniSharp_loglevel), 34 | \ ale#Escape(getcwd()), ale#Escape(s:delimiter), &encoding) 35 | if g:OmniSharp_translate_cygwin_wsl 36 | let cmd = cmd . ' --translate' 37 | endif 38 | return cmd 39 | endfunction 40 | 41 | call ale#linter#Define('cs', { 42 | \ 'name': 'omnisharp', 43 | \ 'aliases': ['Omnisharp', 'OmniSharp'], 44 | \ 'executable': 'python', 45 | \ 'command': function('ale_linters#cs#omnisharp#GetCommand'), 46 | \ 'callback': 'ale_linters#cs#omnisharp#ProcessOutput', 47 | \}) 48 | 49 | " vim:et:sw=2:sts=2 50 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/buffer.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Synchronize the buffer contents with the server. By default, contents are only 5 | " sent when there have been changes since the last run. 6 | " Optional argument: A dict containing the following optional items: 7 | " Callback: funcref to be called after the response is returned (synchronously 8 | " or asynchronously) 9 | " Initializing: flag indicating that this is the first request for this buffer 10 | " SendBuffer: flag indicating that the buffer contents should be sent, 11 | " regardless of &modified status or b:changedtick 12 | function! OmniSharp#actions#buffer#Update(...) abort 13 | let opts = a:0 ? a:1 : {} 14 | let opts.Initializing = get(opts, 'Initializing', 0) 15 | let opts.SendBuffer = opts.Initializing || get(opts, 'SendBuffer', 0) 16 | let bufnr = get(opts, 'bufnr', bufnr('%')) 17 | let bufferValid = OmniSharp#buffer#Valid(bufnr) 18 | let lasttick = get(b:, 'OmniSharp_UpdateChangeTick', -1) 19 | if bufferValid && (opts.SendBuffer || b:changedtick != lasttick) 20 | let b:OmniSharp_UpdateChangeTick = b:changedtick 21 | if g:OmniSharp_server_stdio 22 | let requestOpts = { 23 | \ 'ResponseHandler': function('s:StdioUpdateRH', [opts]), 24 | \ 'Initializing': opts.Initializing 25 | \} 26 | call OmniSharp#stdio#Request('/updatebuffer', requestOpts) 27 | else 28 | if !OmniSharp#IsServerRunning() | return | endif 29 | call OmniSharp#py#Eval('updateBuffer()') 30 | call OmniSharp#py#CheckForError() 31 | if has_key(opts, 'Callback') 32 | call opts.Callback() 33 | endif 34 | endif 35 | elseif has_key(opts, 'Callback') 36 | " If the buffer does not need to be updated, call the Callback immediately 37 | call opts.Callback() 38 | endif 39 | endfunction 40 | 41 | function! s:StdioUpdateRH(opts, response) abort 42 | if has_key(a:opts, 'Callback') 43 | call a:opts.Callback() 44 | endif 45 | endfunction 46 | 47 | let &cpoptions = s:save_cpo 48 | unlet s:save_cpo 49 | 50 | " vim:et:sw=2:sts=2 51 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/codeactions.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " This function returns a count of the currently available code actions. It also 5 | " uses the code actions to pre-populate the code actions for 6 | " OmniSharp#actions#codeactions#Get, and clears them on CursorMoved. 7 | " 8 | " If a single callback function is passed in, the callback will be called on 9 | " CursorMoved, allowing this function to be used to set up a temporary "Code 10 | " actions available" flag, e.g. in the statusline or signs column, and the 11 | " callback function can be used to clear the flag. 12 | " 13 | " If a dict is passed in, the dict may contain one or both of 'CallbackCleanup' 14 | " and 'CallbackCount' Funcrefs. 'CallbackCleanup' is the single callback 15 | " function mentioned above. 'CallbackCount' is called after a response with the 16 | " number of actions available. 17 | " 18 | " call OmniSharp#CountCodeActions({-> execute('sign unplace 99')}) 19 | " call OmniSharp#CountCodeActions({ 20 | " \ 'CallbackCleanup': {-> execute('sign unplace 99')}, 21 | " \ 'CallbackCount': function('PlaceSign') 22 | " \} 23 | function! OmniSharp#actions#codeactions#Count(...) abort 24 | if a:0 && type(a:1) == type(function('tr')) 25 | let opts = { 'CallbackCleanup': a:1 } 26 | elseif a:0 && type(a:1) == type({}) 27 | let opts = a:1 28 | else 29 | let opts = {} 30 | endif 31 | if g:OmniSharp_server_stdio 32 | let Callback = function('s:CBCountCodeActions', [opts]) 33 | call s:StdioGet('normal', Callback) 34 | else 35 | let actions = OmniSharp#py#Eval('getCodeActions("normal")') 36 | if OmniSharp#py#CheckForError() | return | endif 37 | call s:CBCountCodeActions(opts, actions) 38 | endif 39 | endfunction 40 | 41 | function! s:StdioGet(mode, Callback) abort 42 | let opts = { 43 | \ 'ResponseHandler': function('s:StdioGetRH', [a:Callback]), 44 | \ 'SavePosition': 1 45 | \} 46 | call s:PrepareParameters(opts, a:mode) 47 | call OmniSharp#stdio#Request('/v2/getcodeactions', opts) 48 | endfunction 49 | 50 | function! s:PrepareParameters(opts, mode) abort 51 | if a:mode ==# 'visual' 52 | let start = getpos("'<") 53 | let end = getpos("'>") 54 | " In visual line mode, getpos("'>")[2] is a large number (2147483647). 55 | " When this value is too large, use the length of the line as the column 56 | " position. 57 | if end[2] > 99999 58 | let end[2] = len(getline(end[1])) 59 | endif 60 | let s:codeActionParameters = { 61 | \ 'Selection': { 62 | \ 'Start': { 63 | \ 'Line': start[1], 64 | \ 'Column': start[2] 65 | \ }, 66 | \ 'End': { 67 | \ 'Line': end[1], 68 | \ 'Column': end[2] 69 | \ } 70 | \ } 71 | \} 72 | let a:opts.Parameters = s:codeActionParameters 73 | else 74 | if exists('s:codeActionParameters') 75 | unlet s:codeActionParameters 76 | endif 77 | endif 78 | endfunction 79 | 80 | function! s:StdioGetRH(Callback, response) abort 81 | if !a:response.Success | return | endif 82 | call a:Callback(a:response.Body.CodeActions) 83 | endfunction 84 | 85 | function! s:CBCountCodeActions(opts, actions) abort 86 | let s:actions = a:actions 87 | if has_key(a:opts, 'CallbackCount') 88 | call a:opts.CallbackCount(len(s:actions)) 89 | endif 90 | let s:Cleanup = function('s:CleanupCodeActions', [a:opts]) 91 | augroup OmniSharp_CountCodeActions 92 | autocmd! 93 | autocmd CursorMoved call s:Cleanup() 94 | autocmd CursorMovedI call s:Cleanup() 95 | autocmd BufLeave call s:Cleanup() 96 | augroup END 97 | return len(s:actions) 98 | endfunction 99 | 100 | 101 | function! OmniSharp#actions#codeactions#Get(mode) range abort 102 | if exists('s:actions') 103 | call s:CBGetCodeActions(a:mode, s:actions) 104 | elseif g:OmniSharp_server_stdio 105 | let Callback = function('s:CBGetCodeActions', [a:mode]) 106 | call s:StdioGet(a:mode, Callback) 107 | else 108 | let command = printf('getCodeActions(%s)', string(a:mode)) 109 | let actions = OmniSharp#py#Eval(command) 110 | if OmniSharp#py#CheckForError() | return | endif 111 | call s:CBGetCodeActions(a:mode, actions) 112 | endif 113 | endfunction 114 | 115 | function! s:CleanupCodeActions(opts) abort 116 | unlet s:actions 117 | unlet s:Cleanup 118 | if has_key(a:opts, 'CallbackCleanup') 119 | call a:opts.CallbackCleanup() 120 | endif 121 | autocmd! OmniSharp_CountCodeActions 122 | endfunction 123 | 124 | function! s:CBGetCodeActions(mode, actions) abort 125 | if empty(a:actions) 126 | echo 'No code actions found' 127 | return 128 | endif 129 | if g:OmniSharp_selector_ui ==? 'unite' 130 | let context = {'empty': 0, 'auto_resize': 1} 131 | call unite#start([['OmniSharp/findcodeactions', a:mode, a:actions]], context) 132 | elseif g:OmniSharp_selector_ui ==? 'ctrlp' 133 | call ctrlp#OmniSharp#findcodeactions#setactions(a:mode, a:actions) 134 | call ctrlp#init(ctrlp#OmniSharp#findcodeactions#id()) 135 | elseif g:OmniSharp_selector_ui ==? 'fzf' 136 | call fzf#OmniSharp#GetCodeActions(a:mode, a:actions) 137 | elseif g:OmniSharp_selector_ui ==? 'clap' 138 | call clap#OmniSharp#GetCodeActions(a:mode, a:actions) 139 | else 140 | let message = [] 141 | let i = 0 142 | for action in a:actions 143 | let i += 1 144 | call add(message, printf(' %2d. %s', i, action.Name)) 145 | endfor 146 | call add(message, 'Enter an action number, or just hit Enter to cancel: ') 147 | let selection = str2nr(input(join(message, "\n"))) 148 | if type(selection) == type(0) && selection > 0 && selection <= i 149 | let action = a:actions[selection - 1] 150 | if g:OmniSharp_server_stdio 151 | call OmniSharp#actions#codeactions#Run(action) 152 | else 153 | let command = substitute(get(action, 'Identifier'), '''', '\\''', 'g') 154 | let command = printf('runCodeAction(''%s'', ''%s'')', a:mode, command) 155 | let action = OmniSharp#py#Eval(command) 156 | if OmniSharp#py#CheckForError() | return | endif 157 | if !action 158 | echo 'No action taken' 159 | endif 160 | endif 161 | endif 162 | endif 163 | endfunction 164 | 165 | 166 | function! OmniSharp#actions#codeactions#Repeat(mode) abort 167 | if !g:OmniSharp_server_stdio 168 | echomsg 'This functionality is only available with the stdio server' 169 | return 170 | endif 171 | if !exists('s:lastCodeActionIdentifier') 172 | echomsg 'There is no last code action to repeat' 173 | return 174 | endif 175 | call s:PrepareParameters({}, a:mode) 176 | let RH = function('OmniSharp#buffer#PerformChanges', [{}]) 177 | call s:RunCodeAction(s:lastCodeActionIdentifier, 1, RH) 178 | endfunction 179 | 180 | function! OmniSharp#actions#codeactions#Run(action, ...) abort 181 | let RH = function('OmniSharp#buffer#PerformChanges', [a:0 ? a:1 : {}]) 182 | let s:lastCodeActionIdentifier = a:action.Identifier 183 | call s:RunCodeAction(a:action.Identifier, 0, RH) 184 | endfunction 185 | 186 | function! s:RunCodeAction(identifier, repeating, ResponseHandler) abort 187 | let opts = { 188 | \ 'ResponseHandler': a:ResponseHandler, 189 | \ 'Parameters': { 190 | \ 'Identifier': a:identifier, 191 | \ 'WantsTextChanges': 1, 192 | \ 'WantsAllCodeActionOperations': 1 193 | \ }, 194 | \ 'UsePreviousPosition': !a:repeating 195 | \} 196 | if exists('s:codeActionParameters') 197 | call extend(opts.Parameters, s:codeActionParameters, 'force') 198 | endif 199 | call OmniSharp#stdio#Request('/v2/runcodeaction', opts) 200 | endfunction 201 | 202 | let &cpoptions = s:save_cpo 203 | unlet s:save_cpo 204 | 205 | " vim:et:sw=2:sts=2 206 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/codestructure.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#actions#codestructure#Get(bufnr, Callback) abort 5 | let opts = { 6 | \ 'ResponseHandler': function('s:CodeStructureRH', [a:bufnr, a:Callback]), 7 | \ 'BufNum': a:bufnr, 8 | \ 'SendBuffer': 0 9 | \} 10 | call OmniSharp#stdio#Request('/v2/codestructure', opts) 11 | endfunction 12 | 13 | function! s:CodeStructureRH(bufnr, Callback, response) abort 14 | if !a:response.Success | return | endif 15 | call a:Callback(a:bufnr, a:response.Body.Elements) 16 | endfunction 17 | 18 | let &cpoptions = s:save_cpo 19 | unlet s:save_cpo 20 | 21 | " vim:et:sw=2:sts=2 22 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/complete.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:generated_snippets = get(s:, 'generated_snippets', {}) 5 | let s:last_completion_dictionary = get(s:, 'last_completion_dictionary', {}) 6 | 7 | function! OmniSharp#actions#complete#Get(partial, opts) abort 8 | if !OmniSharp#IsServerRunning() 9 | return [] 10 | endif 11 | let opts = type(a:opts) == type({}) ? a:opts : { 'Callback': a:opts } 12 | if g:OmniSharp_server_stdio 13 | let s:complete_pending = 1 14 | call s:StdioGetCompletions(a:partial, opts, function('s:CBGet', [opts])) 15 | if !has_key(opts, 'Callback') 16 | " No callback has been passed in, so this function should return 17 | " synchronously, so it can be used as an omnifunc 18 | let starttime = reltime() 19 | while s:complete_pending && reltimefloat(reltime(starttime)) < g:OmniSharp_timeout 20 | sleep 50m 21 | endwhile 22 | if s:complete_pending | return [] | endif 23 | return s:last_completions 24 | endif 25 | return [] 26 | else 27 | let completions = OmniSharp#py#Eval( 28 | \ printf('getCompletions(%s)', string(a:partial))) 29 | if OmniSharp#py#CheckForError() | let completions = [] | endif 30 | return s:CBGet(opts, completions) 31 | endif 32 | endfunction 33 | 34 | function! OmniSharp#actions#complete#ExpandSnippet() abort 35 | if !g:OmniSharp_want_snippet 36 | return 37 | endif 38 | 39 | if empty(globpath(&runtimepath, 'plugin/UltiSnips.vim')) 40 | call OmniSharp#util#EchoErr('g:OmniSharp_want_snippet is enabled but this requires the UltiSnips plugin and it is not installed.') 41 | return 42 | endif 43 | 44 | let completion = strpart(getline('.'), s:last_startcol, col('.') - 1) 45 | 46 | let should_expand_completion = len(completion) != 0 47 | 48 | if should_expand_completion 49 | let completion = split(completion, '\.')[-1] 50 | let completion = split(completion, 'new ')[-1] 51 | let completion = split(completion, '= ')[-1] 52 | 53 | if has_key(s:last_completion_dictionary, completion) 54 | let snippet = get(get(s:last_completion_dictionary, completion, ''), 'snip','') 55 | if !has_key(s:generated_snippets, completion) 56 | call UltiSnips#AddSnippetWithPriority(completion, snippet, completion, 'iw', 'cs', 1) 57 | let s:generated_snippets[completion] = snippet 58 | endif 59 | call UltiSnips#CursorMoved() 60 | call UltiSnips#ExpandSnippetOrJump() 61 | endif 62 | endif 63 | endfunction 64 | 65 | 66 | function! s:StdioGetCompletions(partial, opts, Callback) abort 67 | let wantDocPopup = OmniSharp#popup#Enabled() 68 | \ && g:omnicomplete_fetch_full_documentation 69 | \ && &completeopt =~# 'popup' 70 | let wantDoc = wantDocPopup ? 'false' 71 | \ : g:omnicomplete_fetch_full_documentation ? 'true' : 'false' 72 | let wantSnippet = g:OmniSharp_want_snippet ? 'true' : g:OmniSharp_coc_snippet ? 'true' : 'false' 73 | let s:last_startcol = has_key(a:opts, 'startcol') 74 | \ ? a:opts.startcol 75 | \ : col('.') - len(a:partial) - 1 76 | let parameters = { 77 | \ 'WordToComplete': a:partial, 78 | \ 'WantDocumentationForEveryCompletionResult': wantDoc, 79 | \ 'WantSnippet': wantSnippet, 80 | \ 'WantMethodHeader': 'true', 81 | \ 'WantKind': 'true', 82 | \ 'WantReturnType': 'true' 83 | \} 84 | let opts = { 85 | \ 'ResponseHandler': function('s:StdioGetCompletionsRH', [a:Callback, wantDocPopup]), 86 | \ 'Parameters': parameters 87 | \} 88 | call OmniSharp#stdio#Request('/autocomplete', opts) 89 | endfunction 90 | 91 | function! s:StdioGetCompletionsRH(Callback, wantDocPopup, response) abort 92 | if !a:response.Success | return | endif 93 | let completions = [] 94 | for cmp in a:response.Body 95 | if g:OmniSharp_want_snippet 96 | let word = cmp.MethodHeader != v:null ? cmp.MethodHeader : cmp.CompletionText 97 | let menu = cmp.ReturnType != v:null ? cmp.ReturnType : cmp.DisplayText 98 | elseif g:OmniSharp_completion_without_overloads && !g:OmniSharp_coc_snippet 99 | let word = cmp.CompletionText 100 | let menu = '' 101 | else 102 | let word = cmp.CompletionText != v:null ? cmp.CompletionText : cmp.MethodHeader 103 | let menu = (cmp.ReturnType != v:null ? cmp.ReturnType . ' ' : '') . 104 | \ (cmp.DisplayText != v:null ? cmp.DisplayText : cmp.MethodHeader) 105 | endif 106 | if word == v:null 107 | continue 108 | endif 109 | let snipCompletionText = get(cmp, 'Snippet', '') 110 | let isSnippet = (snipCompletionText != cmp.CompletionText .. '$0') 111 | \ && (snipCompletionText != cmp.CompletionText) 112 | \ && (!empty(snipCompletionText)) 113 | 114 | let completion = { 115 | \ 'snip': snipCompletionText, 116 | \ 'insertText': isSnippet ? snipCompletionText : '', 117 | \ 'isSnippet': isSnippet, 118 | \ 'word': word, 119 | \ 'menu': menu, 120 | \ 'icase': 1, 121 | \ 'kind': s:ToKind(cmp.Kind), 122 | \ 'dup': g:OmniSharp_completion_without_overloads ? 0 : 1 123 | \} 124 | if a:wantDocPopup 125 | let completion.info = cmp.MethodHeader . "\n ..." 126 | elseif g:omnicomplete_fetch_full_documentation 127 | let completion.info = ' ' 128 | if has_key(cmp, 'Description') && cmp.Description != v:null 129 | let completion.info = cmp.Description 130 | endif 131 | endif 132 | call add(completions, completion) 133 | endfor 134 | call a:Callback(completions, a:wantDocPopup) 135 | endfunction 136 | 137 | function! s:ToKind(roslynKind) 138 | " Values defined in: 139 | " https://github.com/OmniSharp/omnisharp-roslyn/blob/master/src/OmniSharp.Abstractions/Models/v1/Completion/CompletionItem.cs#L104C6-L129C28 140 | let variable = ['Color', 'Event', 'Field', 'Keyword', 'Variable', 'Value'] 141 | let function = ['Constructor', 'Function', 'Method'] 142 | let member = ['Constant', 'EnumMember', 'Property', 'TypeParameter'] 143 | let typedef = ['Class', 'Enum', 'Interface', 'Module', 'Struct'] 144 | return 145 | \ index(variable, a:roslynKind) >= 0 ? 'v' : 146 | \ index(function, a:roslynKind) >= 0 ? 'f' : 147 | \ index(member, a:roslynKind) >= 0 ? 'm' : 148 | \ index(typedef, a:roslynKind) >= 0 ? 't' : '' 149 | endfunction 150 | 151 | function! s:CBGet(opts, completions, ...) abort 152 | let s:last_completions = a:completions 153 | let s:complete_pending = 0 154 | let s:last_completion_dictionary = {} 155 | for completion in a:completions 156 | let s:last_completion_dictionary[get(completion, 'word')] = completion 157 | endfor 158 | if a:0 && a:1 159 | " wantDocPopup 160 | augroup OmniSharp_CompletePopup 161 | autocmd! 162 | autocmd CompleteChanged call s:GetDocumentationDelayed() 163 | augroup END 164 | endif 165 | if has_key(a:opts, 'Callback') 166 | call a:opts.Callback(a:completions) 167 | else 168 | return a:completions 169 | endif 170 | endfunction 171 | 172 | function! s:GetDocumentationDelayed() abort 173 | " Debounce documentation requests, preventing Vim from slowing down while 174 | " CTRL-N'ing through completion results 175 | if exists('s:docTimer') 176 | call timer_stop(s:docTimer) 177 | endif 178 | if !has_key(v:event.completed_item, 'info') 179 | \ || len(v:event.completed_item.info) == 0 180 | return 181 | endif 182 | let s:docTimer = timer_start(get(g:, 'OmniSharpCompletionDocDebounce', 200), 183 | \ function('s:GetDocumentation', [v:event.completed_item])) 184 | endfunction 185 | 186 | function! s:GetDocumentation(completed_item, timer) abort 187 | let info = split(a:completed_item.info, "\n")[0] 188 | let id = popup_findinfo() 189 | if id 190 | if info =~# '(' 191 | call OmniSharp#actions#signature#SignatureHelp({ 192 | \ 'winid': id, 193 | \ 'ForCompleteMethod': info 194 | \}) 195 | else 196 | call OmniSharp#actions#documentation#Documentation({ 197 | \ 'winid': id, 198 | \ 'ForCompletion': info 199 | \}) 200 | endif 201 | endif 202 | endfunction 203 | 204 | let &cpoptions = s:save_cpo 205 | unlet s:save_cpo 206 | 207 | " vim:et:sw=2:sts=2 208 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/definition.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Navigate to the definition of the symbol under the cursor. 5 | " Optional arguments: 6 | " Callback: When a callback is passed in, it is called after the response is 7 | " returned (synchronously or asynchronously) with the found 8 | " location and a flag for whether it is in a file in the project or 9 | " from the metadata. This is done instead of navigating to the found 10 | " location. 11 | " editcommand: The command to use to open buffers, e.g. 'split', 'vsplit', 12 | " 'tabedit' or 'edit' (default). 13 | function! OmniSharp#actions#definition#Find(...) abort 14 | if a:0 && type(a:1) == type(function('tr')) 15 | let Callback = a:1 16 | else 17 | let opts = { 'editcommand': 'edit' } 18 | if a:0 && type(a:1) == type('') && a:1 !=# '' 19 | let opts.editcommand = a:1 20 | endif 21 | let Callback = function('s:CBGotoDefinition', [opts]) 22 | endif 23 | 24 | if g:OmniSharp_server_stdio 25 | call s:StdioFind(Callback) 26 | else 27 | let loc = OmniSharp#py#Eval('gotoDefinition()') 28 | if OmniSharp#py#CheckForError() | return 0 | endif 29 | " We never come from metadata here 30 | return Callback(loc, 0) 31 | endif 32 | endfunction 33 | 34 | function! OmniSharp#actions#definition#Preview() abort 35 | if g:OmniSharp_server_stdio 36 | let Callback = function('s:CBPreviewDefinition') 37 | call s:StdioFind(Callback) 38 | else 39 | let loc = OmniSharp#py#Eval('gotoDefinition()') 40 | if OmniSharp#py#CheckForError() | return 0 | endif 41 | " We never come from metadata here 42 | call s:CBPreviewDefinition(loc, 0) 43 | endif 44 | endfunction 45 | 46 | function! s:StdioFind(Callback) abort 47 | let opts = { 48 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]), 49 | \ 'Parameters': { 50 | \ 'WantMetadata': v:true, 51 | \ } 52 | \} 53 | call OmniSharp#stdio#Request('/gotodefinition', opts) 54 | endfunction 55 | 56 | function! s:StdioFindRH(Callback, response) abort 57 | if !a:response.Success | return | endif 58 | let body = a:response.Body 59 | if type(body) == type({}) && get(body, 'FileName', v:null) != v:null 60 | call a:Callback(OmniSharp#locations#Parse([body])[0], 0) 61 | else 62 | if g:OmniSharp_lookup_metadata 63 | \ && type(body) == type({}) 64 | \ && type(body.MetadataSource) == type({}) 65 | let Callback = function('s:CBMetadataFind', [a:Callback]) 66 | call s:StdioMetadataFind(Callback, body) 67 | else 68 | call a:Callback(0, 1) 69 | endif 70 | endif 71 | endfunction 72 | 73 | function! s:StdioMetadataFind(Callback, metadata) abort 74 | let opts = { 75 | \ 'ResponseHandler': function('s:StdioMetadataFindRH', [a:Callback, a:metadata]), 76 | \ 'Parameters': a:metadata.MetadataSource 77 | \} 78 | call OmniSharp#stdio#Request('/metadata', opts) 79 | endfunction 80 | 81 | function! s:StdioMetadataFindRH(Callback, metadata, response) abort 82 | if !a:response.Success || a:response.Body.Source == v:null | return 0 | endif 83 | call a:Callback(a:response.Body, a:metadata) 84 | endfunction 85 | 86 | function! s:CBMetadataFind(Callback, response, metadata) abort 87 | let host = OmniSharp#GetHost() 88 | let metadata_filename = fnamemodify( 89 | \ OmniSharp#util#TranslatePathForClient(a:response.SourceName), ':t') 90 | let temp_file = OmniSharp#util#TempDir() . '/' . metadata_filename 91 | let lines = split(a:response.Source, "\n", 1) 92 | let lines = map(lines, {i,v -> substitute(v, '\r', '', 'g')}) 93 | call writefile(lines, temp_file, 'b') 94 | let bufnr = bufadd(temp_file) 95 | call setbufvar(bufnr, 'OmniSharp_host', host) 96 | call setbufvar(bufnr, 'OmniSharp_metadata_filename', a:response.SourceName) 97 | let location = { 98 | \ 'filename': temp_file, 99 | \ 'lnum': a:metadata.Line, 100 | \ 'col': a:metadata.Column 101 | \} 102 | call a:Callback(location, 1) 103 | endfunction 104 | 105 | function! s:CBGotoDefinition(opts, location, fromMetadata) abort 106 | if type(a:location) != type({}) " Check whether a dict was returned 107 | echo 'Not found' 108 | let found = 0 109 | else 110 | let found = OmniSharp#locations#Navigate(a:location, get(a:opts, 'editcommand', 'edit')) 111 | if found && a:fromMetadata 112 | setlocal nomodifiable readonly 113 | endif 114 | endif 115 | return found 116 | endfunction 117 | 118 | function! s:CBPreviewDefinition(location, fromMetadata) abort 119 | if type(a:location) != type({}) " Check whether a dict was returned 120 | echo 'Not found' 121 | else 122 | let jumped_from_preview = &previewwindow 123 | call OmniSharp#locations#Preview(a:location) 124 | echo OmniSharp#locations#Modify(a:location).filename 125 | if a:fromMetadata && !jumped_from_preview && &previewwindow 126 | silent wincmd p 127 | endif 128 | endif 129 | endfunction 130 | 131 | let &cpoptions = s:save_cpo 132 | unlet s:save_cpo 133 | 134 | " vim:et:sw=2:sts=2 135 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/diagnostics.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Accepts a Funcref callback argument, to be called after the response is 5 | " returned (synchronously or asynchronously) with the results 6 | function! OmniSharp#actions#diagnostics#Check(...) abort 7 | if !OmniSharp#buffer#Valid() | return [] | endif 8 | let opts = a:0 && a:1 isnot 0 ? { 'Callback': a:1 } : {} 9 | if pumvisible() || !OmniSharp#IsServerRunning() 10 | let b:codecheck = get(b:, 'codecheck', []) 11 | if has_key(opts, 'Callback') 12 | call opts.Callback(b:codecheck) 13 | endif 14 | return b:codecheck 15 | endif 16 | if g:OmniSharp_server_stdio 17 | let Callback = function('s:CBCodeCheck', [opts]) 18 | call OmniSharp#actions#diagnostics#StdioCheck(bufnr('%'), Callback) 19 | else 20 | let codecheck = OmniSharp#py#Eval('codeCheck()') 21 | if OmniSharp#py#CheckForError() | return | endif 22 | return s:CBCodeCheck(opts, codecheck) 23 | endif 24 | endfunction 25 | 26 | " Find all solution/project diagnostics and populate the quickfix list. 27 | " Optional argument: 28 | " Callback: When a callback is passed in, the diagnostics will be sent to 29 | " the callback *instead of* to the quickfix list. 30 | function! OmniSharp#actions#diagnostics#CheckGlobal(...) abort 31 | if !OmniSharp#buffer#Valid() | return [] | endif 32 | if a:0 && a:1 isnot 0 33 | let Callback = a:1 34 | else 35 | let Callback = function('s:CBGlobalCodeCheck') 36 | endif 37 | if g:OmniSharp_server_stdio 38 | let opts = { 39 | \ 'ResponseHandler': function('s:StdioCheckRH', [Callback]) 40 | \} 41 | let job = OmniSharp#GetHost().job 42 | call OmniSharp#stdio#RequestGlobal(job, '/codecheck', opts) 43 | else 44 | let quickfixes = OmniSharp#py#Eval('globalCodeCheck()') 45 | if OmniSharp#py#CheckForError() | return | endif 46 | call Callback(quickfixes) 47 | endif 48 | endfunction 49 | 50 | function! OmniSharp#actions#diagnostics#StdioCheck(bufnr, Callback) abort 51 | " OmniSharp#actions#buffer#Update only updates the server state when the 52 | " buffer has been modified since the last server update. 53 | " When the buffer has been modified, the `/codecheck` request is performed 54 | " after the buffer update is complete. When the buffer has not been modified 55 | " and does not need to be updated, the `/codecheck` request occurs 56 | " immediately. 57 | call OmniSharp#actions#buffer#Update({ 58 | \ 'Callback': function('s:StdioCheck', [a:bufnr, a:Callback]), 59 | \ 'bufnr': a:bufnr 60 | \}) 61 | endfunction 62 | 63 | function! s:StdioCheck(bufnr, Callback) abort 64 | let opts = { 65 | \ 'ResponseHandler': function('s:StdioCheckRH', [a:Callback]), 66 | \ 'BufNum': a:bufnr, 67 | \ 'SendBuffer': 0, 68 | \ 'ReplayOnLoad': 1 69 | \} 70 | call OmniSharp#stdio#Request('/codecheck', opts) 71 | endfunction 72 | 73 | function! s:StdioCheckRH(Callback, response) abort 74 | if !a:response.Success | return | endif 75 | let quickfixes = a:response.Body.QuickFixes 76 | call a:Callback(OmniSharp#actions#diagnostics#Parse(quickfixes)) 77 | endfunction 78 | 79 | function! OmniSharp#actions#diagnostics#Parse(quickfixes) abort 80 | let locations = [] 81 | for quickfix in a:quickfixes 82 | 83 | let exclude_paths = get(g:, 'OmniSharp_diagnostic_exclude_paths', []) 84 | if len(exclude_paths) && has_key(quickfix, 'FileName') 85 | let exclude = 0 86 | for exclude_path in exclude_paths 87 | if match(quickfix.FileName, exclude_path) > 0 88 | let exclude = 1 89 | break 90 | endif 91 | endfor 92 | if exclude 93 | continue 94 | endif 95 | endif 96 | 97 | let overrides = get(g:, 'OmniSharp_diagnostic_overrides', {}) 98 | let diag_id = get(quickfix, 'Id', '-') 99 | if diag_id =~# '.FadeOut$' 100 | " The `FadeOut` analyzers are a VSCode feature and not usable by Vim. 101 | " These diagnostics are always sent as duplicates so just ignore the 102 | " FadeOut diagnostic. 103 | continue 104 | elseif index(keys(overrides), diag_id) >= 0 105 | if overrides[diag_id].type ==? 'None' 106 | continue 107 | endif 108 | call extend(quickfix, overrides[diag_id]) 109 | endif 110 | 111 | let text = get(quickfix, 'Text', get(quickfix, 'Message', '')) 112 | if get(g:, 'OmniSharp_diagnostic_showid') && has_key(quickfix, 'Id') 113 | let text = quickfix.Id . ': ' . text 114 | endif 115 | let location = { 116 | \ 'filename': has_key(quickfix, 'FileName') 117 | \ ? OmniSharp#util#TranslatePathForClient(quickfix.FileName) 118 | \ : expand('%:p'), 119 | \ 'text': text, 120 | \ 'lnum': quickfix.Line, 121 | \ 'col': quickfix.Column, 122 | \ 'vcol': 1 123 | \} 124 | if has_key(quickfix, 'EndLine') && has_key(quickfix, 'EndColumn') 125 | let location.end_lnum = quickfix.EndLine 126 | let location.end_col = quickfix.EndColumn - 1 127 | endif 128 | 129 | if has_key(quickfix, 'type') 130 | let location.type = get(quickfix, 'type') 131 | if has_key(quickfix, 'subtype') 132 | let location.subtype = get(quickfix, 'subtype') 133 | endif 134 | else 135 | let loglevel = get(quickfix, 'LogLevel', '') 136 | if loglevel !=# '' 137 | if loglevel ==# 'Error' 138 | let location.type = 'E' 139 | elseif loglevel ==# 'Info' 140 | let location.type = 'I' 141 | else 142 | let location.type = 'W' 143 | endif 144 | if loglevel ==# 'Hidden' 145 | let location.subtype = 'Style' 146 | endif 147 | endif 148 | endif 149 | 150 | call add(locations, location) 151 | endfor 152 | return locations 153 | endfunction 154 | 155 | function! s:CBCodeCheck(opts, codecheck) abort 156 | let b:codecheck = a:codecheck 157 | if has_key(a:opts, 'Callback') 158 | call a:opts.Callback(a:codecheck) 159 | endif 160 | return b:codecheck 161 | endfunction 162 | 163 | function! s:CBGlobalCodeCheck(quickfixes) abort 164 | if len(a:quickfixes) > 0 165 | call OmniSharp#locations#SetQuickfix(a:quickfixes, 'Code Check Messages') 166 | else 167 | echo 'No Code Check messages' 168 | endif 169 | endfunction 170 | 171 | let &cpoptions = s:save_cpo 172 | unlet s:save_cpo 173 | 174 | " vim:et:sw=2:sts=2 175 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/documentation.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#actions#documentation#TypeLookup(...) abort 5 | let opts = a:0 && a:1 isnot 0 ? { 'Callback': a:1 } : {} 6 | let opts.Doc = g:OmniSharp_typeLookupInPreview 7 | if g:OmniSharp_server_stdio 8 | call s:StdioTypeLookup(opts.Doc, function('s:CBTypeLookup', [opts]), opts) 9 | else 10 | let pycmd = printf('typeLookup(%s)', opts.Doc ? 'True' : 'False') 11 | let response = OmniSharp#py#Eval(pycmd) 12 | if OmniSharp#py#CheckForError() | return | endif 13 | return s:CBTypeLookup(opts, response) 14 | endif 15 | endfunction 16 | 17 | function! OmniSharp#actions#documentation#Documentation(...) abort 18 | let opts = a:0 ? a:1 : {} 19 | let opts.Doc = 1 20 | if g:OmniSharp_server_stdio 21 | call s:StdioTypeLookup(opts.Doc, function('s:CBTypeLookup', [opts]), opts) 22 | else 23 | let pycmd = printf('typeLookup(%s)', opts.Doc ? 'True' : 'False') 24 | let response = OmniSharp#py#Eval(pycmd) 25 | if OmniSharp#py#CheckForError() | return | endif 26 | return s:CBTypeLookup(opts, response) 27 | endif 28 | endfunction 29 | 30 | function! s:StdioTypeLookup(includeDocumentation, Callback, opts) abort 31 | let opts = { 32 | \ 'ResponseHandler': function('s:StdioTypeLookupRH', [a:Callback]), 33 | \ 'Parameters': { 34 | \ 'IncludeDocumentation': a:includeDocumentation ? 'true' : 'false' 35 | \ } 36 | \} 37 | if has_key(a:opts, 'ForCompletion') 38 | " Awkward hacks required. 39 | " When arrow-keys are used instead of CTRL-N/CTRL-P for navigating through 40 | " completion options, we will have lines like this: 41 | " Console.| 42 | " or 43 | " Console.Bee| 44 | " For fetching documentation, we need the full property name, like this: 45 | " Console.Beep| 46 | let line = getline('.') 47 | let col = col('.') 48 | let property = a:opts.ForCompletion 49 | let propertylen = len(property) 50 | let tmpline = line[0 : col - 2] 51 | let add = '' 52 | let added = 0 53 | while added < propertylen && tmpline !~# property . '$' 54 | let add = property[len(property) - 1 :] . add 55 | let property = property[: len(property) - 2] 56 | let added += 1 57 | endwhile 58 | let tmpline .= add . line[col - 1 :] 59 | let opts.OverrideBuffer = { 60 | \ 'Line': tmpline, 61 | \ 'LineNr': line('.'), 62 | \ 'Col': col 63 | \} 64 | endif 65 | call OmniSharp#stdio#Request('/typelookup', opts) 66 | endfunction 67 | 68 | function! s:StdioTypeLookupRH(Callback, response) abort 69 | if !a:response.Success 70 | call a:Callback({ 'Type': '', 'Documentation': '' }) 71 | return 72 | endif 73 | call a:Callback(a:response.Body) 74 | endfunction 75 | 76 | function! s:CBTypeLookup(opts, response) abort 77 | let l:type = a:response.Type != v:null ? a:response.Type : '' 78 | if a:opts.Doc 79 | let content = OmniSharp#util#Trim( 80 | \ l:type . OmniSharp#actions#documentation#Format(a:response, {})) 81 | if OmniSharp#popup#Enabled() 82 | if has_key(a:opts, 'ForCompletion') 83 | " If the popupmenu has already closed, exit early 84 | if !pumvisible() | return | endif 85 | endif 86 | let winid = OmniSharp#popup#Display(content, a:opts) 87 | call setbufvar(winbufnr(winid), '&filetype', 'omnisharpdoc') 88 | call setwinvar(winid, '&conceallevel', 3) 89 | else 90 | let winid = OmniSharp#preview#Display(content, 'Documentation') 91 | endif 92 | else 93 | echo l:type[0 : &columns * &cmdheight - 2] 94 | endif 95 | if has_key(a:opts, 'Callback') 96 | call a:opts.Callback(l:type) 97 | endif 98 | endfunction 99 | 100 | function! OmniSharp#actions#documentation#Format(doc, opts) abort 101 | let content = '' 102 | if has_key(a:doc, 'StructuredDocumentation') 103 | \ && type(a:doc.StructuredDocumentation) == type({}) 104 | let doc = a:doc.StructuredDocumentation 105 | for text in ['Summary', 'Returns', 'Remarks', 'Example', 'Value'] 106 | if get(doc, text . 'Text', '') !=# '' 107 | if text ==# 'Summary' 108 | let content .= "\n\n" . doc[text . 'Text'] 109 | else 110 | let content .= "\n\n## " . text . "\n" . doc[text . 'Text'] 111 | endif 112 | endif 113 | endfor 114 | if get(a:opts, 'ParamsAndExceptions', 1) 115 | if len(doc.ParamElements) 116 | let content .= "\n\n## Parameters" 117 | endif 118 | for param in doc.ParamElements 119 | let content .= "\n`" . param.Name . "`\n" . param.Documentation 120 | endfor 121 | if len(doc.Exception) 122 | let content .= "\n\n## Exceptions" 123 | endif 124 | for exc in doc.Exception 125 | let content .= "\n`" . exc.Name . "`\n" . exc.Documentation 126 | endfor 127 | endif 128 | elseif a:doc.Documentation != v:null 129 | let content .= "\n\n" . a:doc.Documentation 130 | endif 131 | return content 132 | endfunction 133 | 134 | let &cpoptions = s:save_cpo 135 | unlet s:save_cpo 136 | 137 | " vim:et:sw=2:sts=2 138 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/format.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Optionally accepts a callback function. This can be used to write after 5 | " formatting, for example. 6 | function! OmniSharp#actions#format#Format(...) abort 7 | let opts = a:0 && a:1 isnot 0 ? { 'Callback': a:1 } : {} 8 | if g:OmniSharp_server_stdio 9 | if type(get(b:, 'OmniSharp_metadata_filename')) != type('') 10 | call s:StdioFormat(function('s:CBFormat', [opts])) 11 | else 12 | echomsg 'CodeFormat is not supported in metadata files' 13 | endif 14 | else 15 | call OmniSharp#py#Eval('codeFormat()') 16 | call OmniSharp#py#CheckForError() 17 | return s:CBFormat(opts) 18 | endif 19 | endfunction 20 | 21 | function! s:StdioFormat(Callback) abort 22 | let opts = { 23 | \ 'ResponseHandler': function('s:StdioFormatRH', [a:Callback]), 24 | \ 'ExpandTab': &expandtab, 25 | \ 'Parameters': { 26 | \ 'WantsTextChanges': 1 27 | \ } 28 | \} 29 | call OmniSharp#stdio#Request('/codeformat', opts) 30 | endfunction 31 | 32 | function! s:StdioFormatRH(Callback, response) abort 33 | if !a:response.Success | return | endif 34 | normal! m' 35 | let winview = winsaveview() 36 | call OmniSharp#buffer#Update(a:response.Body) 37 | call winrestview(winview) 38 | silent! normal! `` 39 | call a:Callback() 40 | endfunction 41 | 42 | function! s:CBFormat(opts) abort 43 | if has_key(a:opts, 'Callback') 44 | call a:opts.Callback() 45 | endif 46 | endfunction 47 | 48 | let &cpoptions = s:save_cpo 49 | unlet s:save_cpo 50 | 51 | " vim:et:sw=2:sts=2 52 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/highlight_types.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " This is the older highlighting mechanism, where all symbols are fetched from 5 | " the OmniSharp-roslyn, and then highlights are created using matchadd(). 6 | " 7 | " The HTTP server with its python interface can only use this type of 8 | " highlighting, as can older versions of vim without text properties (vim 8) or 9 | " namespaces (neovim). 10 | " 11 | " Use OmniSharp#actions#highlight#Buffer() for full semantic highlighting. 12 | function! OmniSharp#actions#highlight_types#Buffer() abort 13 | if !OmniSharp#buffer#Valid() | return | endif 14 | call OmniSharp#actions#highlight_types#Initialise() 15 | let bufnr = bufnr('%') 16 | if g:OmniSharp_server_stdio 17 | let Callback = function('s:CBHighlightBuffer', [bufnr]) 18 | call s:StdioFindHighlightTypes(bufnr, Callback) 19 | else 20 | if !OmniSharp#IsServerRunning() | return | endif 21 | let hltypes = OmniSharp#py#Eval('findHighlightTypes()') 22 | if OmniSharp#py#CheckForError() | return | endif 23 | call s:CBHighlightBuffer(bufnr, hltypes) 24 | endif 25 | endfunction 26 | 27 | function! s:StdioFindHighlightTypes(bufnr, Callback) abort 28 | let bufferLines = getline(1, '$') 29 | let opts = { 30 | \ 'ResponseHandler': function('s:FindHighlightTypesRH', [a:Callback, bufferLines]), 31 | \ 'BufNum': a:bufnr, 32 | \ 'ReplayOnLoad': 1 33 | \} 34 | call OmniSharp#stdio#Request('/highlight', opts) 35 | endfunction 36 | 37 | function! s:FindHighlightTypesRH(Callback, bufferLines, response) abort 38 | if !a:response.Success | return | endif 39 | let highlights = get(a:response.Body, 'Highlights', []) 40 | let identifierKinds = ['constant name', 'enum member name', 'field name', 41 | \ 'identifier', 'local name', 'parameter name', 'property name', 42 | \ 'static symbol'] 43 | let interfaceKinds = ['interface name'] 44 | let methodKinds = ['extension method name', 'method name'] 45 | let typeKinds = ['class name', 'enum name', 'namespace name', 'struct name'] 46 | let types = [] 47 | for hl in highlights 48 | let lnum = hl.StartLine - 1 49 | if lnum >= len(a:bufferLines) 50 | " An error has occurred with invalid line endings - perhaps a combination 51 | " of unix and dos line endings? 52 | call a:Callback({'error': 'Invalid buffer - check line endings'}) 53 | return 54 | endif 55 | let line = a:bufferLines[lnum] 56 | call add(types, { 57 | \ 'kind': hl.Kind, 58 | \ 'name': line[hl.StartColumn - 1 : hl.EndColumn - 2] 59 | \}) 60 | endfor 61 | 62 | let hltypes = { 63 | \ 'identifiers': map(filter(copy(types), 'index(identifierKinds, v:val.kind) >= 0'), 'v:val.name'), 64 | \ 'interfaces': map(filter(copy(types), 'index(interfaceKinds, v:val.kind) >= 0'), 'v:val.name'), 65 | \ 'methods': map(filter(copy(types), 'index(methodKinds, v:val.kind) >= 0'), 'v:val.name'), 66 | \ 'types': map(filter(copy(types), 'index(typeKinds, v:val.kind) >= 0'), 'v:val.name') 67 | \} 68 | 69 | call a:Callback(hltypes) 70 | endfunction 71 | 72 | function! s:CBHighlightBuffer(bufnr, hltypes) abort 73 | if has_key(a:hltypes, 'error') 74 | echohl WarningMsg | echom a:hltypes.error | echohl None 75 | return 76 | endif 77 | " matchadd() only works in the current window/buffer, so if the user has 78 | " navigated away from the buffer where the request was made, this response can 79 | " not be applied 80 | if bufnr('%') != a:bufnr | return | endif 81 | 82 | let b:OmniSharp_hl_matches = get(b:, 'OmniSharp_hl_matches', []) 83 | 84 | " Clear any matches - highlights with :syn keyword {option} names which cannot 85 | " be created with :syn keyword 86 | for l:matchid in b:OmniSharp_hl_matches 87 | try 88 | call matchdelete(l:matchid) 89 | catch | endtry 90 | endfor 91 | let b:OmniSharp_hl_matches = [] 92 | 93 | call s:Highlight(a:hltypes.identifiers, 'csUserIdentifier') 94 | call s:Highlight(a:hltypes.interfaces, 'csUserInterface') 95 | call s:Highlight(a:hltypes.methods, 'csUserMethod') 96 | call s:Highlight(a:hltypes.types, 'csUserType') 97 | 98 | silent call s:ClearHighlight('csNewType') 99 | syntax region csNewType start="@\@1"hs=s+4 end="[;\n{(<\[]"me=e-1 100 | \ contains=csNew,csUserType,csUserIdentifier 101 | endfunction 102 | 103 | function! s:ClearHighlight(groupname) 104 | try 105 | execute 'syntax clear' a:groupname 106 | catch | endtry 107 | endfunction 108 | 109 | function! s:Highlight(types, group) abort 110 | silent call s:ClearHighlight(a:group) 111 | if empty(a:types) 112 | return 113 | endif 114 | let l:types = uniq(sort(a:types)) 115 | 116 | " Cannot use vim syntax options as keywords, so remove types with these 117 | " names. See :h :syn-keyword /Note 118 | let l:opts = split('cchar conceal concealends contained containedin ' . 119 | \ 'contains display extend fold nextgroup oneline skipempty skipnl ' . 120 | \ 'skipwhite transparent') 121 | 122 | " Create a :syn-match for each type with an option name. 123 | let l:illegal = filter(copy(l:types), {i,v -> index(l:opts, v, 0, 1) >= 0}) 124 | for l:ill in l:illegal 125 | let matchid = matchadd(a:group, '\<' . l:ill . '\>') 126 | call add(b:OmniSharp_hl_matches, matchid) 127 | endfor 128 | 129 | call filter(l:types, {i,v -> index(l:opts, v, 0, 1) < 0}) 130 | 131 | if len(l:types) 132 | execute 'syntax keyword' a:group join(l:types) 133 | endif 134 | endfunction 135 | 136 | function! OmniSharp#actions#highlight_types#Initialise() abort 137 | if get(s:, 'highlightsInitialized') | return | endif 138 | let s:highlightsInitialized = 1 139 | highlight default link csUserIdentifier Identifier 140 | highlight default link csUserInterface Include 141 | highlight default link csUserMethod Function 142 | highlight default link csUserType Type 143 | endfunction 144 | 145 | let &cpoptions = s:save_cpo 146 | unlet s:save_cpo 147 | 148 | " vim:et:sw=2:sts=2 149 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/implementations.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Accepts a Funcref callback argument, to be called after the response is 5 | " returned (synchronously or asynchronously) with the list of found locations. 6 | " This is done instead of navigating to them or showing a quick-fix. 7 | function! OmniSharp#actions#implementations#Find(...) abort 8 | if a:0 && a:1 isnot 0 9 | let Callback = a:1 10 | else 11 | let target = expand('') 12 | let Callback = function('s:CBFindImplementations', [target]) 13 | endif 14 | 15 | if g:OmniSharp_server_stdio 16 | call s:StdioFind(Callback) 17 | else 18 | let locs = OmniSharp#py#Eval('findImplementations()') 19 | if OmniSharp#py#CheckForError() | return | endif 20 | return Callback(locs) 21 | endif 22 | endfunction 23 | 24 | function! OmniSharp#actions#implementations#Preview() abort 25 | if g:OmniSharp_server_stdio 26 | let Callback = function('s:CBPreviewImplementation') 27 | call s:StdioFind(Callback) 28 | else 29 | let locs = OmniSharp#py#Eval('findImplementations()') 30 | if OmniSharp#py#CheckForError() | return | endif 31 | call s:CBPreviewImplementation(locs) 32 | endif 33 | endfunction 34 | 35 | function! s:StdioFind(Callback) abort 36 | let opts = { 37 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]) 38 | \} 39 | call OmniSharp#stdio#Request('/findimplementations', opts) 40 | endfunction 41 | 42 | function! s:StdioFindRH(Callback, response) abort 43 | if !a:response.Success | return | endif 44 | let responses = a:response.Body.QuickFixes 45 | if type(responses) == type([]) 46 | call a:Callback(OmniSharp#locations#Parse(responses)) 47 | else 48 | call a:Callback([]) 49 | endif 50 | endfunction 51 | 52 | function! s:CBFindImplementations(target, locations) abort 53 | let numImplementations = len(a:locations) 54 | if numImplementations == 0 55 | echo 'No implementations found' 56 | elseif numImplementations == 1 57 | call OmniSharp#locations#Navigate(a:locations[0]) 58 | else " numImplementations > 1 59 | let locations = OmniSharp#locations#Modify(a:locations) 60 | call OmniSharp#locations#SetQuickfix(locations, 61 | \ 'Implementations: ' . a:target) 62 | endif 63 | return numImplementations 64 | endfunction 65 | 66 | function! s:CBPreviewImplementation(locations, ...) abort 67 | let numImplementations = len(a:locations) 68 | if numImplementations == 0 69 | echo 'No implementations found' 70 | else 71 | call OmniSharp#locations#Preview(a:locations[0]) 72 | let filename = OmniSharp#locations#Modify(a:locations[0]).filename 73 | if numImplementations == 1 74 | echo filename 75 | else 76 | echo filename . ': Implementation 1 of ' . numImplementations 77 | endif 78 | endif 79 | endfunction 80 | 81 | let &cpoptions = s:save_cpo 82 | unlet s:save_cpo 83 | 84 | " vim:et:sw=2:sts=2 85 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/members.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Accepts a Funcref callback argument, to be called after the response is 5 | " returned (synchronously or asynchronously) with the list of found locations 6 | " of members. 7 | " This is done instead of showing a quick-fix. 8 | function! OmniSharp#actions#members#Find(...) abort 9 | if a:0 && a:1 isnot 0 10 | let Callback = a:1 11 | else 12 | let Callback = function('s:CBFindMembers') 13 | endif 14 | 15 | if g:OmniSharp_server_stdio 16 | call s:StdioFind(Callback) 17 | else 18 | let locs = OmniSharp#py#Eval('findMembers()') 19 | if OmniSharp#py#CheckForError() | return | endif 20 | return Callback(locs) 21 | endif 22 | endfunction 23 | 24 | function! s:StdioFind(Callback) abort 25 | let opts = { 26 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]) 27 | \} 28 | call OmniSharp#stdio#Request('/v2/codestructure', opts) 29 | endfunction 30 | 31 | function! s:StdioFindRH(Callback, response) abort 32 | if !a:response.Success | return | endif 33 | call a:Callback(s:ParseCodeStructure(a:response.Body)) 34 | endfunction 35 | 36 | function! s:ParseCodeStructure(responseBody) abort 37 | let locations = [] 38 | let filename = expand('%:p') 39 | for element in a:responseBody.Elements 40 | call s:ParseCodeStructureItemRec(element, filename, locations) 41 | endfor 42 | return locations 43 | endfunction 44 | 45 | function! s:ParseCodeStructureItemRec(item, filename, locations) abort 46 | call add(a:locations, s:ParseCodeStructureItem(a:item, a:filename)) 47 | let children = get(a:item, 'Children', []) 48 | if type(children) == type([]) 49 | for child in children 50 | call s:ParseCodeStructureItemRec(child, a:filename, a:locations) 51 | endfor 52 | endif 53 | endfunction 54 | 55 | function! s:ParseCodeStructureItem(item, filename) abort 56 | return { 57 | \ 'filename': a:filename, 58 | \ 'lnum': a:item.Ranges.name.Start.Line, 59 | \ 'col': a:item.Ranges.name.Start.Column, 60 | \ 'end_lnum': a:item.Ranges.name.End.Line, 61 | \ 'end_col': a:item.Ranges.name.End.Column - 1, 62 | \ 'text': s:ComputeItemSignature(a:item), 63 | \ 'vcol': 1 64 | \} 65 | endfunction 66 | 67 | function! s:ComputeItemSignature(item) abort 68 | if type(a:item.Properties) != type({}) 69 | return get(a:item, 'Kind', '') . ' ' . a:item.DisplayName 70 | endif 71 | let line = a:item.Ranges.name.Start.Line 72 | let endcol = a:item.Ranges.name.Start.Column - 2 73 | let textBeforeDisplayName = substitute(getline(line)[:endcol], '^\s*', '', '') 74 | if textBeforeDisplayName !~# '^\(private\|internal\|protected\|public\)' 75 | let textBeforeDisplayName = a:item.Properties.accessibility . ' ' . textBeforeDisplayName 76 | endif 77 | return s:ReduceToOneCharacter(textBeforeDisplayName) . a:item.DisplayName 78 | endfunction 79 | 80 | let s:SingleCharacterSymbolByAccessModifier = { 81 | \ 'public': '+', 82 | \ 'private': '-', 83 | \ 'internal': '&', 84 | \ 'protected': '|' 85 | \} 86 | 87 | function! s:ReduceToOneCharacter(textBeforeDisplayName) abort 88 | let accessModifier = matchlist(a:textBeforeDisplayName, '\w\+')[0] 89 | return s:SingleCharacterSymbolByAccessModifier[accessModifier] . a:textBeforeDisplayName[len(accessModifier):] 90 | endfunction 91 | 92 | function! s:CBFindMembers(locations) abort 93 | let numMembers = len(a:locations) 94 | if numMembers > 0 95 | if get(g:, 'OmniSharp_selector_findmembers', '') == 'fzf' 96 | call fzf#OmniSharp#FindMembers(a:locations, 'Members') 97 | else 98 | call OmniSharp#locations#SetQuickfixWithVerticalAlign(a:locations, 'Members') 99 | endif 100 | endif 101 | return numMembers 102 | endfunction 103 | 104 | let &cpoptions = s:save_cpo 105 | unlet s:save_cpo 106 | 107 | " vim:et:sw=2:sts=2 108 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/navigate.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Navigate to the next member definition in the class. 5 | " Optional arguments: 6 | " Callback: When a callback is passed in, it is called after the response is 7 | " returned with the member location. No navigation is performed when a 8 | " callback is passed in. 9 | function! OmniSharp#actions#navigate#Down(...) abort 10 | call s:Navigate(1, a:0 ? a:1 : function('OmniSharp#locations#Navigate')) 11 | endfunction 12 | 13 | " See OmniSharp#actions#navigate#Down 14 | function! OmniSharp#actions#navigate#Up(...) abort 15 | call s:Navigate(0, a:0 ? a:1 : function('OmniSharp#locations#Navigate')) 16 | endfunction 17 | 18 | function! s:Navigate(down, Callback) abort 19 | if g:OmniSharp_server_stdio 20 | let RH = function('s:StdioNavigateRH', [a:Callback]) 21 | let opts = { 'ResponseHandler': RH } 22 | call OmniSharp#stdio#Request(a:down ? '/navigatedown' : '/navigateup', opts) 23 | else 24 | let loc = OmniSharp#py#Eval(a:down ? 'navigateDown()' : 'navigateUp()') 25 | if OmniSharp#py#CheckForError() | return | endif 26 | call a:Callback(loc) 27 | endif 28 | endfunction 29 | 30 | function! s:StdioNavigateRH(Callback, response) abort 31 | if !a:response.Success | return | endif 32 | call a:Callback(OmniSharp#locations#Parse([a:response.Body])[0]) 33 | endfunction 34 | 35 | let &cpoptions = s:save_cpo 36 | unlet s:save_cpo 37 | 38 | " vim:et:sw=2:sts=2 39 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/project.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#actions#project#Get(bufnr, Callback) abort 5 | if has_key(OmniSharp#GetHost(a:bufnr), 'project') 6 | call a:Callback(v:true) 7 | return 8 | endif 9 | let opts = { 10 | \ 'ResponseHandler': function('s:ProjectRH', [a:Callback, a:bufnr]), 11 | \ 'BufNum': a:bufnr, 12 | \ 'SendBuffer': 0 13 | \} 14 | call OmniSharp#stdio#Request('/project', opts) 15 | endfunction 16 | 17 | function! s:ProjectRH(Callback, bufnr, response) abort 18 | if !a:response.Success 19 | call a:Callback(v:false) 20 | else 21 | let host = getbufvar(a:bufnr, 'OmniSharp_host') 22 | let host.project = a:response.Body 23 | call a:Callback(v:true) 24 | endif 25 | endfunction 26 | 27 | function! PrintProjectLoadFailed() abort 28 | echohl ErrorMsg 29 | echomsg 'Failure getting project info. Check :OmniSharpOpenLog' 30 | echohl None 31 | endfunction 32 | 33 | function! OmniSharp#actions#project#DebugProject(stopAtEntry, ...) abort 34 | if !OmniSharp#util#HasVimspector() 35 | echohl WarningMsg 36 | echomsg 'Vimspector required to debug project' 37 | echohl None 38 | return 39 | endif 40 | let bufnr = bufnr('%') 41 | function! DebugProjectCb(bufnr, stopAtEntry, args, success) abort 42 | let project = getbufvar(a:bufnr, 'OmniSharp_host').project 43 | " Make sure we're not running on a csx script 44 | if !a:success 45 | call PrintProjectLoadFailed() 46 | elseif project.ScriptProject is v:null 47 | let programPath = project.MsBuildProject.TargetPath 48 | if has('win32') | let programPath = substitute(programPath, '\', '/', 'g') | endif 49 | call vimspector#LaunchWithConfigurations({ 50 | \ 'launch': { 51 | \ 'adapter': 'netcoredbg', 52 | \ 'configuration': { 53 | \ 'request': 'launch', 54 | \ 'program': programPath, 55 | \ 'args': a:args, 56 | \ 'stopAtEntry#json': a:stopAtEntry ? 'true' : 'false' 57 | \ } 58 | \ } 59 | \}) 60 | else 61 | echohl WarningMsg 62 | echomsg 'DebugProject is not currently implemented for csx files' 63 | echohl None 64 | endif 65 | endfunction 66 | call OmniSharp#actions#project#Get(bufnr, function('DebugProjectCb', [bufnr, a:stopAtEntry, a:000])) 67 | endfunction 68 | 69 | function! OmniSharp#actions#project#CreateDebugConfig(stopAtEntry, ...) abort 70 | let bufnr = bufnr('%') 71 | function! CreateDebugConfigCb(bufnr, stopAtEntry, args, success) abort 72 | if !a:success 73 | call PrintProjectLoadFailed() 74 | else 75 | let host = getbufvar(a:bufnr, 'OmniSharp_host') 76 | let programPath = host.project.MsBuildProject.TargetPath 77 | if has('win32') | let programPath = substitute(programPath, '\', '/', 'g') | endif 78 | let contents = [ 79 | \' {', 80 | \' "configurations": {', 81 | \' "attach": {', 82 | \' "adapter": "netcoredbg",', 83 | \' "configuration": {', 84 | \' "request": "attach",', 85 | \' "processId": "${pid}"', 86 | \' }', 87 | \' },', 88 | \' "launch": {', 89 | \' "adapter": "netcoredbg",', 90 | \' "configuration": {', 91 | \' "request": "launch",', 92 | \' "program": "'.programPath.'",', 93 | \' "args": ' . json_encode(a:args) . ',', 94 | \' "stopAtEntry": ' . (a:stopAtEntry ? 'true' : 'false'), 95 | \' }', 96 | \' }', 97 | \' }', 98 | \' }', 99 | \ ] 100 | if isdirectory(host.sln_or_dir) 101 | let hostdir = host.sln_or_dir 102 | else 103 | let hostdir = fnamemodify(host.sln_or_dir, ':h:p') 104 | endif 105 | let filename = hostdir . '/.vimspector.json' 106 | call writefile(contents, filename) 107 | execute 'edit ' . filename 108 | endif 109 | if !OmniSharp#util#HasVimspector() 110 | echohl WarningMsg 111 | echomsg 'Vimspector does not seem to be installed. You will need it to run the created configuration.' 112 | echohl None 113 | endif 114 | endfunction 115 | call OmniSharp#actions#project#Get(bufnr, function('CreateDebugConfigCb', [bufnr, a:stopAtEntry, a:000])) 116 | endfunction 117 | 118 | function! OmniSharp#actions#project#Complete(arglead, cmdline, cursorpos) abort 119 | let job = OmniSharp#GetHost(bufnr()).job 120 | if !has_key(job, 'projects') | return [] | endif 121 | let projectPaths = map(copy(job.projects), {_,p -> fnamemodify(p.path, ':.')}) 122 | return filter(projectPaths, {_,path -> path =~? a:arglead}) 123 | endfunction 124 | 125 | function! OmniSharp#actions#project#Reload(projectFile) abort 126 | if len(a:projectFile) == 0 127 | call s:ReloadProjectForBuffer(bufnr()) 128 | return 129 | endif 130 | if !filereadable(a:projectFile) 131 | call OmniSharp#util#EchoErr('File ' . a:projectFile . ' cannot be read') 132 | return 133 | endif 134 | echohl Title 135 | echomsg 'Reloading ' . fnamemodify(a:projectFile, ':t') 136 | echohl None 137 | let opts = { 138 | \ 'SendBuffer': 0, 139 | \ 'Arguments': [{ 140 | \ 'FileName': fnamemodify(a:projectFile, ':p'), 141 | \ 'ChangeType': 'Change' 142 | \ }] 143 | \} 144 | let job = OmniSharp#GetHost(bufnr()).job 145 | let job.loaded = 0 146 | let job.projects_loaded -= 1 147 | let job.restart_time = reltime() 148 | let job.restart_project = fnamemodify(a:projectFile, ':t') 149 | call OmniSharp#stdio#Request('/filesChanged', opts) 150 | endfunction 151 | 152 | function! s:ReloadProjectForBuffer(bufnr) abort 153 | call OmniSharp#actions#project#Get(a:bufnr, function('s:ReloadCB', [a:bufnr])) 154 | endfunction 155 | 156 | function! s:ReloadCB(bufnr, success) abort 157 | if a:success 158 | let project = OmniSharp#GetHost(a:bufnr).project 159 | let projectFile = project.MsBuildProject.Path 160 | call OmniSharp#actions#project#Reload(projectFile) 161 | else 162 | echohl WarningMsg 163 | echomsg 'Project could not be found. Try reloading the project by name.' 164 | echohl None 165 | endif 166 | endfunction 167 | 168 | let &cpoptions = s:save_cpo 169 | unlet s:save_cpo 170 | 171 | " vim:et:sw=2:sts=2 172 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/rename.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#actions#rename#Prompt() abort 5 | let renameto = inputdialog('Rename to: ', expand('')) 6 | if renameto !=# '' 7 | call OmniSharp#actions#rename#To(renameto) 8 | endif 9 | endfunction 10 | 11 | function! OmniSharp#actions#rename#To(renameto, ...) abort 12 | let opts = a:0 && a:1 isnot 0 ? { 'Callback': a:1 } : {} 13 | if g:OmniSharp_server_stdio 14 | call s:StdioRename(a:renameto, opts) 15 | else 16 | let command = printf('renameTo(%s)', string(a:renameto)) 17 | let changes = OmniSharp#py#Eval(command) 18 | if OmniSharp#py#CheckForError() | return | endif 19 | 20 | let save_lazyredraw = &lazyredraw 21 | let save_eventignore = &eventignore 22 | let buf = bufnr('%') 23 | let curpos = getpos('.') 24 | let view = winsaveview() 25 | try 26 | set lazyredraw eventignore=all 27 | for change in changes 28 | execute 'silent hide edit' fnameescape(change.FileName) 29 | let modified = &modified 30 | let content = split(change.Buffer, '\r\?\n') 31 | silent % delete _ 32 | silent 1put =content 33 | silent 1 delete _ 34 | if !modified 35 | silent update 36 | endif 37 | endfor 38 | finally 39 | if bufnr('%') != buf 40 | exec 'buffer ' . buf 41 | endif 42 | call setpos('.', curpos) 43 | call winrestview(view) 44 | silent update 45 | let &eventignore = save_eventignore 46 | silent edit " reload to apply syntax 47 | let &lazyredraw = save_lazyredraw 48 | endtry 49 | if has_key(opts, 'Callback') 50 | call opts.Callback() 51 | endif 52 | endif 53 | endfunction 54 | 55 | function! s:StdioRename(renameto, opts) abort 56 | let opts = { 57 | \ 'ResponseHandler': function('OmniSharp#buffer#PerformChanges', [a:opts]), 58 | \ 'Parameters': { 59 | \ 'RenameTo': a:renameto, 60 | \ 'WantsTextChanges': 1 61 | \ } 62 | \} 63 | call OmniSharp#stdio#Request('/rename', opts) 64 | endfunction 65 | 66 | let &cpoptions = s:save_cpo 67 | unlet s:save_cpo 68 | 69 | " vim:et:sw=2:sts=2 70 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/signature.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:seq = get(s:, 'seq', 0) 5 | 6 | function! OmniSharp#actions#signature#SignatureHelp(...) abort 7 | let opts = a:0 ? a:1 : {} 8 | if !has_key(opts, 'ForCompleteMethod') 9 | augroup OmniSharp_signature_help_insert 10 | autocmd! 11 | " Update the signature help box when new text is inserted. 12 | autocmd TextChangedI 13 | \ call OmniSharp#actions#signature#SignatureHelp() 14 | 15 | " Remove this augroup when leaving insert mode 16 | autocmd InsertLeave 17 | \ autocmd! OmniSharp_signature_help_insert 18 | augroup END 19 | endif 20 | if g:OmniSharp_server_stdio 21 | call s:StdioSignatureHelp(function('s:CBSignatureHelp', [opts]), opts) 22 | else 23 | let response = OmniSharp#py#Eval('signatureHelp()') 24 | if OmniSharp#py#CheckForError() | return | endif 25 | call s:CBSignatureHelp(opts, response) 26 | endif 27 | endfunction 28 | 29 | function! s:StdioSignatureHelp(Callback, opts) abort 30 | let s:seq += 1 31 | let opts = { 32 | \ 'ResponseHandler': function('s:StdioSignatureHelpRH', 33 | \ [a:Callback, s:seq, a:opts]) 34 | \} 35 | if has_key(a:opts, 'ForCompleteMethod') 36 | " Awkward hacks required: 37 | if !g:OmniSharp_want_snippet 38 | " We are requesting signatureHelp from a completion popup. This means our 39 | " line currently looks something like this: 40 | " Console.Write| 41 | " However, OmniSharp-roslyn will only provide signatureHelp when the cursor 42 | " follows a full method name with opening parenthesis, like this: 43 | " Console.Write(| 44 | " We therefore need to add a '(' to the request and move the cursor 45 | " position. 46 | " 47 | " When arrow-keys are used instead of CTRL-N, the method name is _not_ 48 | " inserted, so instead of: 49 | " Console.Write| 50 | " we just have: 51 | " Console.| 52 | " or 53 | " Console.Wri| 54 | " In this case, we need to add/complete the method name as well as the '(' 55 | " in our request buffer. 56 | let line = getline('.') 57 | let col = col('.') 58 | let method = substitute(a:opts.ForCompleteMethod, '(.*$', '', '') 59 | let methodlen = len(method) 60 | let tmpline = line[0 : col - 2] 61 | let add = '' 62 | let added = 0 63 | while added < methodlen && tmpline !~# method . '$' 64 | let add = method[len(method) - 1 :] . add 65 | let method = method[: len(method) - 2] 66 | let added += 1 67 | endwhile 68 | let tmpline .= add . '(' . line[col - 1 :] 69 | let opts.OverrideBuffer = { 70 | \ 'Line': tmpline, 71 | \ 'LineNr': line('.'), 72 | \ 'Col': col + added + 1 73 | \} 74 | else 75 | " When g:OmniSharp_want_snippet == 1, the line returned from 76 | " OmniSharp-roslyn is different, and currently looks like this: 77 | " Console.Write(.....)| 78 | " We don't need to modify this line, but we _do_ need to place the cursor 79 | " inside the parentheses. 80 | let opts.OverrideBuffer = { 81 | \ 'Line': getline('.'), 82 | \ 'LineNr': line('.'), 83 | \ 'Col': col('.') - 1 84 | \} 85 | endif 86 | endif 87 | call OmniSharp#stdio#Request('/signaturehelp', opts) 88 | endfunction 89 | 90 | function! s:StdioSignatureHelpRH(Callback, seq, opts, response) abort 91 | if !a:response.Success | return | endif 92 | if s:seq != a:seq 93 | " Another SignatureHelp request has been made so ignore this response and 94 | " wait for the latest response to complete 95 | return 96 | endif 97 | if has_key(a:opts, 'ForCompleteMethod') && !g:OmniSharp_want_snippet 98 | " Because of our 'falsified' request with an extra '(', re-synchronise the 99 | " server's version of the buffer with the actual buffer contents. 100 | call OmniSharp#actions#buffer#Update({'SendBuffer': 1}) 101 | endif 102 | call a:Callback(a:response.Body) 103 | endfunction 104 | 105 | function! s:CBSignatureHelp(opts, response) abort 106 | if type(a:response) != type({}) 107 | if !has_key(a:opts, 'ForCompleteMethod') 108 | echo 'No signature help found' 109 | endif 110 | if !OmniSharp#popup#Enabled() 111 | " Clear existing preview content 112 | call OmniSharp#preview#Display('', 'SignatureHelp') 113 | endif 114 | return 115 | endif 116 | let s:last = { 117 | \ 'Signatures': a:response.Signatures, 118 | \ 'SigIndex': a:response.ActiveSignature, 119 | \ 'ParamIndex': a:response.ActiveParameter, 120 | \ 'EmphasizeActiveParam': 1, 121 | \ 'ParamsAndExceptions': 0, 122 | \ 'mode': mode() 123 | \} 124 | if has_key(a:opts, 'ForCompleteMethod') 125 | " If the popupmenu has already closed, exit early 126 | if !pumvisible() | return | endif 127 | let s:last.PopupMaps = 0 128 | let s:last.EmphasizeActiveParam = 0 129 | let s:last.ParamsAndExceptions = 1 130 | let idx = 0 131 | for signature in a:response.Signatures 132 | if stridx(signature.Label, a:opts.ForCompleteMethod) >= 0 133 | let s:last.SigIndex = idx 134 | break 135 | endif 136 | let idx += 1 137 | endfor 138 | endif 139 | if has_key(a:opts, 'winid') 140 | let s:last.winid = a:opts.winid 141 | endif 142 | call OmniSharp#actions#signature#Display(0, 0) 143 | endfunction 144 | 145 | function! OmniSharp#actions#signature#Display(deltaSig, deltaParam) abort 146 | let isig = s:last.SigIndex + a:deltaSig 147 | let isig = 148 | \ isig < 0 ? len(s:last.Signatures) - 1 : 149 | \ isig >= len(s:last.Signatures) ? 0 : isig 150 | if isig == -1 151 | return 152 | endif 153 | let s:last.SigIndex = isig 154 | let signature = s:last.Signatures[isig] 155 | 156 | let content = signature.Label 157 | if s:last.EmphasizeActiveParam && len(s:last.Signatures) > 1 158 | let content .= printf("\n (overload %d of %d)", 159 | \ isig + 1, len(s:last.Signatures)) 160 | endif 161 | 162 | let emphasis = {} 163 | if s:last.EmphasizeActiveParam && len(signature.Parameters) 164 | let iparam = s:last.ParamIndex + a:deltaParam 165 | let iparam = 166 | \ iparam < 0 ? 0 : 167 | \ iparam >= len(signature.Parameters) ? len(signature.Parameters) - 1 : iparam 168 | let s:last.ParamIndex = iparam 169 | let parameter = signature.Parameters[iparam] 170 | 171 | let content .= printf("\n\n`%s`: %s", 172 | \ parameter.Name, parameter.Documentation) 173 | let pos = matchstrpos(signature.Label, parameter.Label) 174 | if pos[1] >= 0 && pos[2] > pos[1] 175 | let emphasis = { 'start': pos[1] + 1, 'length': len(parameter.Label) } 176 | endif 177 | endif 178 | 179 | let content .= OmniSharp#actions#documentation#Format(signature, { 180 | \ 'ParamsAndExceptions': s:last.ParamsAndExceptions 181 | \}) 182 | 183 | if OmniSharp#popup#Enabled() 184 | let opts = {} 185 | if has_key(s:last, 'winid') 186 | let opts.winid = s:last.winid 187 | endif 188 | if has_key(s:last, 'mode') 189 | let opts.mode = s:last.mode 190 | endif 191 | let winid = OmniSharp#popup#Display(content, opts) 192 | call setbufvar(winbufnr(winid), '&filetype', 'omnisharpdoc') 193 | call setwinvar(winid, '&conceallevel', 3) 194 | if get(s:last, 'PopupMaps', 1) 195 | call OmniSharp#popup#Map(s:last.mode, 'sigNext', '', 196 | \ 'OmniSharp#actions#signature#Display(1, 0)') 197 | call OmniSharp#popup#Map(s:last.mode, 'sigPrev', '', 198 | \ 'OmniSharp#actions#signature#Display(-1, 0)') 199 | call OmniSharp#popup#Map(s:last.mode, 'sigParamNext', '', 200 | \ 'OmniSharp#actions#signature#Display(0, 1)') 201 | call OmniSharp#popup#Map(s:last.mode, 'sigParamPrev', '', 202 | \ 'OmniSharp#actions#signature#Display(0, -1)') 203 | endif 204 | else 205 | let winid = OmniSharp#preview#Display(content, 'SignatureHelp') 206 | endif 207 | if has_key(emphasis, 'start') 208 | if !has('nvim') && has('textprop') 209 | let propTypes = prop_type_list({'bufnr': winbufnr(winid)}) 210 | if index(propTypes, 'OmniSharpActiveParameter') < 0 211 | call prop_type_add('OmniSharpActiveParameter', { 212 | \ 'bufnr': winbufnr(winid), 213 | \ 'highlight': 'OmniSharpActiveParameter' 214 | \}) 215 | endif 216 | call prop_add(1, emphasis.start, { 217 | \ 'length': emphasis.length, 218 | \ 'bufnr': winbufnr(winid), 219 | \ 'type': 'OmniSharpActiveParameter' 220 | \}) 221 | elseif has('nvim') && exists('*nvim_create_namespace') 222 | let nsid = nvim_create_namespace('OmniSharp_signature_emphasis') 223 | call nvim_buf_add_highlight(winbufnr(winid), nsid, 224 | \ 'OmniSharpActiveParameter', 225 | \ 0, emphasis.start - 1, emphasis.start + emphasis.length - 1) 226 | endif 227 | endif 228 | redraw 229 | endfunction 230 | 231 | let &cpoptions = s:save_cpo 232 | unlet s:save_cpo 233 | 234 | " vim:et:sw=2:sts=2 235 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/symbols.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Find all project symbols, or all symbols including a search substring. Symbol 5 | " locations are loaded in the configured selector, :help g:OmniSharp_selector_ui 6 | " Optional arguments: 7 | " symbolName: Partial name of the symbol to search for. 8 | " Callback: When a callback is passed in, it is called after the response is 9 | " returned (synchronously or asynchronously) with the found symbol 10 | " locations. 11 | function! OmniSharp#actions#symbols#Find(...) abort 12 | if a:0 && type(a:1) == type('') 13 | let filter = a:1 14 | elseif a:0 > 1 && type(a:2) == type('') 15 | let filter = a:2 16 | else 17 | let filter = '' 18 | endif 19 | if a:0 && type(a:1) == type(function('tr')) 20 | let Callback = a:1 21 | elseif a:0 > 1 && type(a:2) == type(function('tr')) 22 | let Callback = a:2 23 | else 24 | let Callback = function('s:CBFindSymbol', [filter]) 25 | endif 26 | call s:Find(filter, 'TypeAndMember', Callback) 27 | endfunction 28 | 29 | " Find all project types. This function is similar to 30 | " OmniSharp#actions#symbols#Find() but returns fewer results, and can be 31 | " significanltly faster in a large codebase. 32 | function! OmniSharp#actions#symbols#FindType(...) abort 33 | if a:0 && type(a:1) == type('') 34 | let filter = a:1 35 | elseif a:0 > 1 && type(a:2) == type('') 36 | let filter = a:2 37 | else 38 | let filter = '' 39 | endif 40 | if a:0 && type(a:1) == type(function('tr')) 41 | let Callback = a:1 42 | elseif a:0 > 1 && type(a:2) == type(function('tr')) 43 | let Callback = a:2 44 | else 45 | let Callback = function('s:CBFindSymbol', [filter]) 46 | endif 47 | call s:Find(filter, 'Type', Callback) 48 | endfunction 49 | 50 | function! s:Find(filter, symbolfilter, Callback) abort 51 | if !OmniSharp#IsServerRunning() | return | endif 52 | if g:OmniSharp_server_stdio 53 | call s:StdioFind(a:filter, a:symbolfilter, a:Callback) 54 | else 55 | let locs = OmniSharp#py#Eval(printf('findSymbols(%s, %s)', string(a:filter), string(a:symbolfilter))) 56 | if OmniSharp#py#CheckForError() | return | endif 57 | return a:Callback(locs) 58 | endif 59 | endfunction 60 | 61 | function! s:StdioFind(filter, symbolfilter, Callback) abort 62 | let opts = { 63 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]), 64 | \ 'Parameters': { 'Filter': a:filter, 'SymbolFilter': a:symbolfilter } 65 | \} 66 | call OmniSharp#stdio#Request('/findsymbols', opts) 67 | endfunction 68 | 69 | function! s:StdioFindRH(Callback, response) abort 70 | if !a:response.Success | return | endif 71 | call a:Callback(OmniSharp#locations#Parse(a:response.Body.QuickFixes)) 72 | endfunction 73 | 74 | function! s:CBFindSymbol(filter, locations) abort 75 | if empty(a:locations) 76 | echo 'No symbols found' 77 | return 78 | endif 79 | let locations = OmniSharp#locations#Modify(a:locations) 80 | if g:OmniSharp_selector_ui ==? 'clap' 81 | call clap#OmniSharp#FindSymbols(locations) 82 | elseif g:OmniSharp_selector_ui ==? 'unite' 83 | call unite#start([['OmniSharp/findsymbols', locations]]) 84 | elseif g:OmniSharp_selector_ui ==? 'ctrlp' 85 | call ctrlp#OmniSharp#findsymbols#setsymbols(locations) 86 | call ctrlp#init(ctrlp#OmniSharp#findsymbols#id()) 87 | elseif g:OmniSharp_selector_ui ==? 'fzf' 88 | call fzf#OmniSharp#FindSymbols(locations) 89 | else 90 | let title = 'Symbols' . (len(a:filter) ? ': ' . a:filter : '') 91 | call OmniSharp#locations#SetQuickfix(locations, title) 92 | endif 93 | endfunction 94 | 95 | let &cpoptions = s:save_cpo 96 | unlet s:save_cpo 97 | 98 | " vim:et:sw=2:sts=2 99 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/typedefinition.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Navigate to the definition of the symbol under the cursor. 5 | " Optional arguments: 6 | " Callback: When a callback is passed in, it is called after the response is 7 | " returned (synchronously or asynchronously) with the found 8 | " location and a flag for whether it is in a file in the project or 9 | " from the metadata. This is done instead of navigating to the found 10 | " location. 11 | " editcommand: The command to use to open buffers, e.g. 'split', 'vsplit', 12 | " 'tabedit' or 'edit' (default). 13 | function! OmniSharp#actions#typedefinition#Find(...) abort 14 | let opts = { 'editcommand': 'edit' } 15 | if a:0 && type(a:1) == type('') && a:1 !=# '' 16 | let opts.editcommand = a:1 17 | endif 18 | 19 | let Callback = function('s:CBGotoDefinition', [opts]) 20 | 21 | call s:StdioFind(Callback) 22 | endfunction 23 | 24 | function! s:StdioFind(Callback) abort 25 | let opts = { 26 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]), 27 | \ 'Parameters': { 28 | \ 'WantMetadata': v:true, 29 | \ } 30 | \} 31 | call OmniSharp#stdio#Request('/gototypedefinition', opts) 32 | endfunction 33 | 34 | function! s:StdioFindRH(Callback, response) abort 35 | if !a:response.Success | return | endif 36 | let body = a:response.Body 37 | if type(body) == type({}) && get(body, 'Definitions', v:null) != v:null 38 | let definition = body.Definitions[0] 39 | 40 | if g:OmniSharp_lookup_metadata 41 | \ && type(definition) == type({}) 42 | \ && type(definition.MetadataSource) == type({}) 43 | let Callback = function('s:CBMetadataFind', [a:Callback]) 44 | call s:StdioMetadataFind(Callback, definition) 45 | else 46 | let location = OmniSharp#locations#ParseLocation(definition.Location) 47 | 48 | call a:Callback(location, 0) 49 | endif 50 | endif 51 | endfunction 52 | 53 | function! s:StdioMetadataFind(Callback, definition) abort 54 | let metadataSource = a:definition.MetadataSource 55 | let metadataSource.TypeName = substitute(metadataSource.TypeName, '?', '', 'g') 56 | 57 | let opts = { 58 | \ 'ResponseHandler': function('s:StdioMetadataFindRH', [a:Callback, a:definition]), 59 | \ 'Parameters': metadataSource 60 | \} 61 | call OmniSharp#stdio#Request('/metadata', opts) 62 | endfunction 63 | 64 | function! s:StdioMetadataFindRH(Callback, metadata, response) abort 65 | if !a:response.Success || a:response.Body.Source == v:null | return 0 | endif 66 | call a:Callback(a:response.Body, a:metadata) 67 | endfunction 68 | 69 | function! s:CBMetadataFind(Callback, response, definition) abort 70 | let host = OmniSharp#GetHost() 71 | let metadata_filename = fnamemodify( 72 | \ OmniSharp#util#TranslatePathForClient(a:response.SourceName), ':t') 73 | let temp_file = OmniSharp#util#TempDir() . '/' . metadata_filename 74 | let lines = split(a:response.Source, "\n", 1) 75 | let lines = map(lines, {i,v -> substitute(v, '\r', '', 'g')}) 76 | call writefile(lines, temp_file, 'b') 77 | let bufnr = bufadd(temp_file) 78 | call setbufvar(bufnr, 'OmniSharp_host', host) 79 | call setbufvar(bufnr, 'OmniSharp_metadata_filename', a:response.SourceName) 80 | let location = { 81 | \ 'filename': temp_file, 82 | \ 'lnum': a:definition.Location.Range.Start.Line, 83 | \ 'col': a:definition.Location.Range.Start.Column 84 | \} 85 | call a:Callback(location, 1) 86 | endfunction 87 | 88 | function! s:CBGotoDefinition(opts, location, fromMetadata) abort 89 | if type(a:location) != type({}) " Check whether a dict was returned 90 | echo 'Not found' 91 | 92 | let found = 0 93 | else 94 | let found = OmniSharp#locations#Navigate(a:location, get(a:opts, 'editcommand', 'edit')) 95 | if found && a:fromMetadata 96 | setlocal nomodifiable readonly 97 | endif 98 | endif 99 | return found 100 | endfunction 101 | 102 | let &cpoptions = s:save_cpo 103 | unlet s:save_cpo 104 | 105 | " vim:et:sw=2:sts=2 106 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/usages.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Find usages of the symbol under the cursor. 5 | " Optional argument: 6 | " Callback: When a callback is passed in, the usage locations will be sent to 7 | " the callback *instead of* to the configured selector 8 | " (g:OmniSharp_selector_findusages) or quickfix list. 9 | function! OmniSharp#actions#usages#Find(...) abort 10 | if a:0 && a:1 isnot 0 11 | let Callback = a:1 12 | else 13 | let target = expand('') 14 | let Callback = function('s:CBFindUsages', [target]) 15 | endif 16 | 17 | if g:OmniSharp_server_stdio 18 | call s:StdioFind(Callback) 19 | else 20 | let locs = OmniSharp#py#Eval('findUsages()') 21 | if OmniSharp#py#CheckForError() | return | endif 22 | return Callback(locs) 23 | endif 24 | endfunction 25 | 26 | function! s:StdioFind(Callback) abort 27 | let opts = { 28 | \ 'ResponseHandler': function('s:StdioFindRH', [a:Callback]), 29 | \ 'Parameters': { 30 | \ 'ExcludeDefinition': 1 31 | \ } 32 | \} 33 | call OmniSharp#stdio#Request('/findusages', opts) 34 | endfunction 35 | 36 | function! s:StdioFindRH(Callback, response) abort 37 | if !a:response.Success | return | endif 38 | let usages = a:response.Body.QuickFixes 39 | if type(usages) == type([]) 40 | call a:Callback(OmniSharp#locations#Parse(usages)) 41 | else 42 | call a:Callback([]) 43 | endif 44 | endfunction 45 | 46 | function! s:CBFindUsages(target, locations) abort 47 | let numUsages = len(a:locations) 48 | if numUsages == 0 49 | echo 'No usages found' 50 | return 0 51 | endif 52 | 53 | let locations = OmniSharp#locations#Modify(a:locations) 54 | if get(g:, 'OmniSharp_selector_findusages', '') ==? 'fzf' 55 | call fzf#OmniSharp#FindUsages(locations, a:target) 56 | elseif get(g:, 'OmniSharp_selector_findusages', '') ==? 'clap' 57 | call clap#OmniSharp#FindUsages(locations, a:target) 58 | else 59 | call OmniSharp#locations#SetQuickfix(locations, 'Usages: ' . a:target) 60 | endif 61 | return numUsages 62 | endfunction 63 | 64 | let &cpoptions = s:save_cpo 65 | unlet s:save_cpo 66 | 67 | " vim:et:sw=2:sts=2 68 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/usings.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | " Accepts a Funcref callback argument, to be called after the response is 5 | " returned (synchronously or asynchronously) with the list of locations of 6 | " ambiguous usings. 7 | " This is done instead of showing a quick-fix. 8 | function! OmniSharp#actions#usings#Fix(...) abort 9 | if a:0 && a:1 isnot 0 10 | let Callback = a:1 11 | else 12 | let Callback = function('s:CBFixUsings') 13 | endif 14 | 15 | let bufnr = bufnr('%') 16 | if g:OmniSharp_server_stdio 17 | call s:StdioFix(Callback, bufnr) 18 | else 19 | let locs = OmniSharp#py#Eval('fixUsings()') 20 | if OmniSharp#py#CheckForError() | return | endif 21 | return Callback(locs, bufnr) 22 | endif 23 | endfunction 24 | 25 | function! s:StdioFix(Callback, bufnr) abort 26 | let opts = { 27 | \ 'ResponseHandler': function('s:StdioFixRH', [a:Callback, a:bufnr]), 28 | \ 'Parameters': { 29 | \ 'WantsTextChanges': 1 30 | \ } 31 | \} 32 | call OmniSharp#stdio#Request('/fixusings', opts) 33 | endfunction 34 | 35 | function! s:StdioFixRH(Callback, bufnr, response) abort 36 | if !a:response.Success | return | endif 37 | normal! m' 38 | let winview = winsaveview() 39 | let frombufname = bufname('%') 40 | let frombufnr = bufnr('%') 41 | if a:bufnr != frombufnr 42 | call OmniSharp#locations#Navigate({ 43 | \ 'filename': bufname(a:bufnr) 44 | \}, 'silent') 45 | endif 46 | call OmniSharp#buffer#Update(a:response.Body) 47 | if bufnr('%') != frombufnr 48 | call OmniSharp#locations#Navigate({ 49 | \ 'filename': frombufname 50 | \}, 'silent') 51 | endif 52 | call winrestview(winview) 53 | silent! normal! `` 54 | if type(a:response.Body.AmbiguousResults) == type(v:null) 55 | call a:Callback([]) 56 | else 57 | call a:Callback(OmniSharp#locations#Parse(a:response.Body.AmbiguousResults)) 58 | endif 59 | endfunction 60 | 61 | function! s:CBFixUsings(locations) abort 62 | let numAmbiguous = len(a:locations) 63 | if numAmbiguous > 0 64 | let locations = OmniSharp#locations#Modify(a:locations) 65 | call OmniSharp#locations#SetQuickfix(locations, 'Ambiguous usings') 66 | endif 67 | return numAmbiguous 68 | endfunction 69 | 70 | let &cpoptions = s:save_cpo 71 | unlet s:save_cpo 72 | 73 | " vim:et:sw=2:sts=2 74 | -------------------------------------------------------------------------------- /autoload/OmniSharp/actions/workspace.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:attempts = 0 5 | 6 | function! OmniSharp#actions#workspace#Get(job) abort 7 | let opts = { 8 | \ 'ResponseHandler': function('s:ProjectsRH', [a:job]) 9 | \} 10 | let s:attempts += 1 11 | call OmniSharp#stdio#RequestGlobal(a:job, '/projects', opts) 12 | endfunction 13 | 14 | function! s:ProjectsRH(job, response) abort 15 | " If this request fails, retry up to 5 times 16 | if !a:response.Success 17 | if s:attempts < 5 18 | call OmniSharp#actions#workspace#Get(a:job) 19 | endif 20 | return 21 | endif 22 | " If no projects have been loaded by the time this callback is reached, there 23 | " are no projects and the job can be marked as ready 24 | let projects = get(get(a:response.Body, 'MsBuild', {}), 'Projects', {}) 25 | let a:job.projects = map(projects, 26 | \ {_,project -> {"name": project.AssemblyName, "path": project.Path, "target": project.TargetPath}}) 27 | if get(a:job, 'projects_total', 0) > 0 28 | call OmniSharp#log#Log(a:job, 'Workspace complete: ' . a:job.projects_total . ' project(s)') 29 | else 30 | call OmniSharp#log#Log(a:job, 'Workspace complete: no projects') 31 | call OmniSharp#project#RegisterLoaded(a:job) 32 | endif 33 | endfunction 34 | 35 | let &cpoptions = s:save_cpo 36 | unlet s:save_cpo 37 | 38 | " vim:et:sw=2:sts=2 39 | -------------------------------------------------------------------------------- /autoload/OmniSharp/buffer.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#buffer#Initialize(job, bufnr, command, opts) abort 5 | let a:job.pending_requests = get(a:job, 'pending_requests', {}) 6 | let host = getbufvar(a:bufnr, 'OmniSharp_host') 7 | if get(host, 'initialized') | return | endif 8 | let a:job.pending_requests[a:bufnr] = get(a:job.pending_requests, a:bufnr, {}) 9 | " More recent requests to the same command replace older pending requests 10 | let a:job.pending_requests[a:bufnr][a:command] = a:opts 11 | if has_key(OmniSharp#GetHost(a:bufnr), 'initializing') | return | endif 12 | let host.initializing = 1 13 | call OmniSharp#actions#buffer#Update({ 14 | \ 'bufnr': a:bufnr, 15 | \ 'Callback': function('s:CBInitialize', [a:job, a:bufnr, host]), 16 | \ 'Initializing': 1 17 | \}) 18 | endfunction 19 | 20 | function! s:CBInitialize(job, bufnr, host) abort 21 | let a:host.initialized = 1 22 | unlet a:host.initializing 23 | call OmniSharp#log#Log(a:job, 'Replaying requests for buffer ' . a:bufnr) 24 | for key in keys(a:job.pending_requests[a:bufnr]) 25 | call OmniSharp#stdio#Request(key, a:job.pending_requests[a:bufnr][key]) 26 | unlet a:job.pending_requests[a:bufnr][key] 27 | if empty(a:job.pending_requests[a:bufnr]) 28 | unlet a:job.pending_requests[a:bufnr] 29 | endif 30 | endfor 31 | endfunction 32 | 33 | function! OmniSharp#buffer#PerformChanges(opts, response) abort 34 | if !a:response.Success | return | endif 35 | let changes = get(a:response.Body, 'Changes', []) 36 | if type(changes) != type([]) || len(changes) == 0 37 | echo 'No action taken' 38 | else 39 | let winview = winsaveview() 40 | let bufname = bufname('%') 41 | let bufnr = bufnr('%') 42 | let unload_bufnrs = [] 43 | let hidden_bak = &hidden | set hidden 44 | let fileencoding = &fileencoding 45 | let bomb = &bomb 46 | for change in changes 47 | let modificationType = get(change, 'ModificationType', 0) 48 | if modificationType == 0 " Modified 49 | call OmniSharp#locations#Navigate({ 50 | \ 'filename': OmniSharp#util#TranslatePathForClient(change.FileName), 51 | \}, 'silent') 52 | call OmniSharp#buffer#Update(change) 53 | if bufnr('%') != bufnr 54 | let c = get(change, 'Changes', []) 55 | if &bomb != bomb 56 | let &bomb = bomb 57 | endif 58 | if len(c) == 1 && &fileencoding != fileencoding 59 | \ && c[0].StartLine == 1 && c[0].StartColumn == 1 60 | \ && c[0].EndLine == 1 && c[0].EndColumn == 1 61 | " New file with different file encoding 62 | execute 'silent write ++enc=' . fileencoding 63 | else 64 | silent write 65 | endif 66 | silent edit 67 | endif 68 | elseif modificationType == 1 " Opened 69 | " ModificationType 1 is typically done in conjunction with a rename 70 | " (ModificationType 2) 71 | let bufname = OmniSharp#util#TranslatePathForClient(change.FileName) 72 | let bufnr = bufadd(bufname) 73 | " neovim requires that the buffer be explicitly loaded 74 | call bufload(bufnr) 75 | elseif modificationType == 2 " Renamed 76 | let oldbufname = OmniSharp#util#TranslatePathForClient(change.FileName) 77 | let oldbufnr = bufadd(oldbufname) 78 | call add(unload_bufnrs, oldbufnr) 79 | endif 80 | endfor 81 | if bufnr('%') != bufnr 82 | call OmniSharp#locations#Navigate({ 83 | \ 'filename': bufname 84 | \}, 'silent') 85 | endif 86 | for unload_bufnr in unload_bufnrs 87 | " Don't worry about unwritten changes when there has been a rename - the 88 | " buffer contents were sent along with the code-action request, so the 89 | " modified contents are what has been written. 90 | execute 'bwipeout!' unload_bufnr 91 | endfor 92 | call winrestview(winview) 93 | let [line, col] = getpos("'`")[1:2] 94 | if line > 1 && col > 1 95 | silent! normal! `` 96 | endif 97 | let &hidden = hidden_bak 98 | endif 99 | if has_key(a:opts, 'Callback') 100 | call a:opts.Callback() 101 | endif 102 | endfunction 103 | 104 | function! OmniSharp#buffer#Update(responseBody) abort 105 | let changes = get(a:responseBody, 'Changes', []) 106 | if type(changes) == type(v:null) | let changes = [] | endif 107 | 108 | let virtualedit_bak = &virtualedit 109 | let &l:virtualedit = 'all' 110 | if len(changes) 111 | for change in changes 112 | let text = join(split(change.NewText, '\r\?\n', 1), "\n") 113 | let startCol = OmniSharp#util#CharToByteIdx( 114 | \ bufnr('%'), change.StartLine, change.StartColumn) 115 | let endCol = OmniSharp#util#CharToByteIdx( 116 | \ bufnr('%'), change.EndLine, change.EndColumn) 117 | let start = [change.StartLine, startCol] 118 | let end = [change.EndLine, endCol] 119 | call cursor(start) 120 | call cursor(change.EndLine, max([1, endCol - 1])) 121 | let lineLen = len(getline('.')) 122 | if change.StartLine < change.EndLine && (endCol == 1 || lineLen == 0) 123 | " We can't delete before the first character of the line, so add an 124 | " extra charaqcter which will be immediately deleted again 125 | noautocmd normal! i> 126 | elseif start == end 127 | " Start and end are the same so insert a character to be replaced 128 | if startCol > 1 129 | normal! l 130 | endif 131 | noautocmd normal! i= 132 | endif 133 | call setpos("'[", [0, change.StartLine, startCol]) 134 | let paste_bak = &paste | set paste 135 | try 136 | silent execute "noautocmd keepjumps normal! v`[c\=text\" 137 | catch 138 | " E685: Internal error: no text property below deleted line 139 | endtry 140 | let &paste = paste_bak 141 | endfor 142 | elseif get(a:responseBody, 'Buffer', v:null) != v:null 143 | let pos = getpos('.') 144 | let lines = split(a:responseBody.Buffer, '\r\?\n', 1) 145 | if len(lines) < line('$') 146 | if exists('*deletebufline') 147 | call deletebufline('%', len(lines) + 1, '$') 148 | else 149 | %delete 150 | endif 151 | endif 152 | call setline(1, lines) 153 | let pos[1] = min([pos[1], line('$')]) 154 | call setpos('.', pos) 155 | endif 156 | let &l:virtualedit = virtualedit_bak 157 | endfunction 158 | 159 | function! OmniSharp#buffer#Valid(...) abort 160 | let bufnr = a:0 ? a:1 : bufnr('%') 161 | let bufname = fnamemodify(bufname(bufnr), ':p') 162 | let buftype = a:0 ? getbufvar(a:1, '&buftype') : &buftype 163 | return buftype !=# 'nofile' && bufname !=# '' 164 | \ && match(bufname, '\vfugitive:(///|\\\\)') != 0 165 | \ && (!exists('*g:OmniSharp_buffer_valid') || g:OmniSharp_buffer_valid(bufnr)) 166 | endfunction 167 | 168 | let &cpoptions = s:save_cpo 169 | unlet s:save_cpo 170 | 171 | " vim:et:sw=2:sts=2 172 | -------------------------------------------------------------------------------- /autoload/OmniSharp/locations.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:dir_separator = fnamemodify('.', ':p')[-1 :] 5 | 6 | function! OmniSharp#locations#Modify(locations) abort 7 | " a:locations may be either a single 'quickfix' location, or list of locations 8 | let locs = copy(type(a:locations) == type([]) ? a:locations : [a:locations]) 9 | for location in locs 10 | let location.filename = OmniSharp#locations#ModifyPath(location.filename) 11 | endfor 12 | return type(a:locations) == type([]) ? locs : locs[0] 13 | endfunction 14 | 15 | function! OmniSharp#locations#ModifyPath(filename) abort 16 | let modifiers = get(g:, 'OmniSharp_filename_modifiers', ':.') 17 | 18 | if modifiers ==# 'relative' 19 | let filename = fnamemodify(a:filename, ':p') 20 | let common = escape(getcwd(), '\') 21 | let relpath = substitute(filename, '^' . common . s:dir_separator, '', '') 22 | let relprefix = '' 23 | while relpath ==# filename && common !=# fnamemodify(common, ':h') 24 | let common = fnamemodify(common, ':h') 25 | let relpath = substitute(filename, '^' . common . s:dir_separator, '', '') 26 | let relprefix .= '..' . s:dir_separator 27 | endwhile 28 | if common !=# fnamemodify(common, ':h') 29 | return relprefix . relpath 30 | endif 31 | let modifiers = ':p' 32 | endif 33 | 34 | return fnamemodify(a:filename, modifiers) 35 | endfunction 36 | 37 | " Navigate to location. 38 | " a:location: A location dict, or list of location dicts. The location or 39 | " locations have the same format as a quickfix list entry. 40 | " See :help setqflist-what 41 | " Optional argument: 42 | " editcommand: The command to use to open buffers, e.g. 'split', 'vsplit', 43 | " 'tabedit' or 'edit' (default). 44 | " Pass 'silent' to perform a silent navigation, with no autocmds 45 | " executed. 46 | function! OmniSharp#locations#Navigate(location, ...) abort 47 | let locations = type(a:location) == type([]) ? a:location : [a:location] 48 | let navigated = 0 49 | for loc in locations 50 | if loc.filename !=# '' 51 | " Update the ' mark, adding this location to the jumplist. 52 | normal! m' 53 | let editcommand = 'edit' 54 | if a:0 55 | if type(a:1) == type(0) 56 | let editcommand = a:1 ? 'silent' : 'edit' 57 | else 58 | let editcommand = a:1 59 | endif 60 | endif 61 | let noautocmd = editcommand ==# 'silent' 62 | if noautocmd 63 | let editcommand = 'edit' 64 | endif 65 | let changebuffer = fnamemodify(loc.filename, ':p') !=# expand('%:p') 66 | if changebuffer || editcommand !=# 'edit' 67 | if &modified && !&hidden && editcommand ==# 'edit' 68 | let editcommand = 'split' 69 | endif 70 | if noautocmd 71 | let editcommand = 'noautocmd ' . editcommand 72 | endif 73 | execute editcommand fnameescape(loc.filename) 74 | endif 75 | if get(loc, 'lnum', 0) > 0 76 | let col = get(loc, 'vcol', 0) 77 | \ ? OmniSharp#util#CharToByteIdx(loc.filename, loc.lnum, loc.col) 78 | \ : loc.col 79 | call cursor(loc.lnum, col) 80 | redraw 81 | endif 82 | let navigated = 1 83 | endif 84 | endfor 85 | return navigated 86 | endfunction 87 | 88 | function! OmniSharp#locations#ParseLocation(value) abort 89 | return { 90 | \ 'filename': has_key(a:value, 'FileName') 91 | \ ? OmniSharp#util#TranslatePathForClient(a:value.FileName) 92 | \ : expand('%:p'), 93 | \ 'lnum': a:value.Range.Start.Line, 94 | \ 'col': a:value.Range.Start.Column, 95 | \ 'end_lnum': a:value.Range.End.Line, 96 | \ 'end_col': a:value.Range.End.Column - 1, 97 | \ 'vcol': 1 98 | \} 99 | endfunction 100 | 101 | function! OmniSharp#locations#Parse(quickfixes) abort 102 | let locations = [] 103 | for quickfix in a:quickfixes 104 | let location = { 105 | \ 'filename': has_key(quickfix, 'FileName') 106 | \ ? OmniSharp#util#TranslatePathForClient(quickfix.FileName) 107 | \ : expand('%:p'), 108 | \ 'text': get(quickfix, 'Text', get(quickfix, 'Message', '')), 109 | \ 'lnum': quickfix.Line, 110 | \ 'col': quickfix.Column, 111 | \ 'vcol': 1 112 | \} 113 | if has_key(quickfix, 'EndLine') && has_key(quickfix, 'EndColumn') 114 | let location.end_lnum = quickfix.EndLine 115 | let location.end_col = quickfix.EndColumn - 1 116 | endif 117 | 118 | call add(locations, location) 119 | endfor 120 | 121 | return locations 122 | endfunction 123 | 124 | function! OmniSharp#locations#Preview(location) abort 125 | if OmniSharp#popup#Enabled() 126 | let bufnr = bufadd(a:location.filename) 127 | " neovim requires that the buffer be explicitly loaded 128 | call bufload(bufnr) 129 | call OmniSharp#popup#Buffer(bufnr, a:location.lnum, {}) 130 | else 131 | call OmniSharp#preview#File(a:location.filename, a:location.lnum, a:location.col) 132 | endif 133 | endfunction 134 | 135 | function! OmniSharp#locations#SetQuickfix(list, title, ...) abort 136 | let what = {'title': a:title} 137 | if a:0 138 | call extend(what, a:1) 139 | endif 140 | call s:SetQuickfixFromDict(a:list, what) 141 | endfunction 142 | 143 | function! OmniSharp#locations#SetQuickfixWithVerticalAlign(list, title) abort 144 | " setqflist 'what' argument 145 | let what = { 146 | \ 'title': a:title, 147 | \ 'quickfixtextfunc': function('s:QuickfixTextFuncAlign') 148 | \} 149 | call s:SetQuickfixFromDict(a:list, what) 150 | endfunction 151 | 152 | function! s:SetQuickfixFromDict(list, what) abort 153 | if !has('patch-8.0.0657') 154 | \ || setqflist([], ' ', extend(a:what, {'nr': '$', 'items': a:list})) == -1 155 | call setqflist(a:list) 156 | endif 157 | silent doautocmd QuickFixCmdPost OmniSharp 158 | if g:OmniSharp_open_quickfix 159 | botright cwindow 160 | endif 161 | endfunction 162 | 163 | function! s:QuickfixTextFuncAlign(info) abort 164 | if a:info.quickfix 165 | let qfl = getqflist({'id': a:info.id, 'items': 0}).items 166 | else 167 | let qfl = getloclist(a:info.winid, {'id': a:info.id, 'items': 0}).items 168 | endif 169 | let l = [] 170 | let efm_type = {'e': 'error', 'w': 'warning', 'i': 'info', 'n': 'note'} 171 | let lnum_width = len(max(map(range(a:info.start_idx - 1, a:info.end_idx - 1), { _,v -> qfl[v].lnum }))) 172 | let col_width = len(max(map(range(a:info.start_idx - 1, a:info.end_idx - 1), {_, v -> qfl[v].col}))) 173 | let fname_width = max(map(range(a:info.start_idx - 1, a:info.end_idx - 1), {_, v -> strchars(fnamemodify(bufname(qfl[v].bufnr), ':t'), 1)})) 174 | let type_width = max(map(range(a:info.start_idx - 1, a:info.end_idx - 1), {_, v -> strlen(get(efm_type, qfl[v].type, ''))})) 175 | let errnum_width = len(max(map(range(a:info.start_idx - 1, a:info.end_idx - 1),{_, v -> qfl[v].nr}))) 176 | for idx in range(a:info.start_idx - 1, a:info.end_idx - 1) 177 | let e = qfl[idx] 178 | if !e.valid 179 | call add(l, '|| ' . e.text) 180 | else 181 | if e.lnum == 0 && e.col == 0 182 | call add(l, bufname(e.bufnr)) 183 | else 184 | let fname = fnamemodify(printf('%-*S', fname_width, bufname(e.bufnr)), ':t') 185 | let lnum = printf('%*d', lnum_width, e.lnum) 186 | let col = printf('%*d', col_width, e.col) 187 | let type = printf('%-*S', type_width, get(efm_type, e.type, '')) 188 | let errnum = '' 189 | if e.nr 190 | let errnum = printf('%*d', errnum_width + 1, e.nr) 191 | endif 192 | call add(l, printf('%s|%s col %s %s%s| %s', fname, lnum, col, type, errnum, e.text)) 193 | endif 194 | endif 195 | endfor 196 | return l 197 | endfunction 198 | 199 | let &cpoptions = s:save_cpo 200 | unlet s:save_cpo 201 | 202 | " vim:et:sw=2:sts=2 203 | -------------------------------------------------------------------------------- /autoload/OmniSharp/log.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | if has('win32') 5 | let default_log_dir = expand(':p:h:h:h') . '\log' 6 | else 7 | let default_log_dir = expand(':p:h:h:h') . '/log' 8 | end 9 | 10 | let s:logdir = get(g:, 'OmniSharp_log_dir', default_log_dir) 11 | let s:stdiologfile = s:logdir . '/stdio.log' 12 | 13 | " Make the log directory if it doesn't exist 14 | if !isdirectory(s:logdir) 15 | call mkdir(s:logdir, 'p') 16 | end 17 | 18 | function! OmniSharp#log#GetLogDir() abort 19 | return s:logdir 20 | endfunction 21 | 22 | " Log from OmniSharp-vim 23 | function! OmniSharp#log#Log(job, message, ...) abort 24 | if g:OmniSharp_loglevel ==? 'none' | return | endif 25 | call s:Init(a:job) 26 | let debug = a:0 && a:1 27 | if g:OmniSharp_loglevel !=? 'info' || !debug 28 | call writefile([a:message], a:job.logfile, 'a') 29 | endif 30 | endfunction 31 | 32 | " Log a decoded server message 33 | function! OmniSharp#log#LogServer(job, raw, msg) abort 34 | if g:OmniSharp_loglevel ==? 'none' | return | endif 35 | call s:Init(a:job) 36 | if get(g:, 'OmniSharp_proc_debug') 37 | call writefile([a:raw], a:job.logfile, 'a') 38 | elseif !has_key(a:msg, 'Body') || type(a:msg.Body) != type({}) 39 | return 40 | elseif !has_key(a:msg, 'Event') 41 | return 42 | elseif get(a:msg, 'Event', '') ==# 'log' 43 | " Attempt to normalise newlines, which can be \%uD\%u0 in Windows and \%u0 44 | " in linux 45 | let message = substitute(a:msg.Body.Message, '\%uD\ze\%u0', '', 'g') 46 | let lines = split(message, '\%u0', 1) 47 | if a:msg.Body.Name ==# 'OmniSharp.Roslyn.BufferManager' 48 | let line0 = ' ' . lines[0] 49 | if lines[0] =~# '^\s*Updating file .\+ with new text:$' 50 | " Strip the trailing ':' 51 | let line0 = line0[:-2] 52 | endif 53 | " The server sends the full content of the buffer. Don't log it. 54 | let prefix = s:LogLevelPrefix(a:msg.Body.LogLevel) 55 | let lines = [printf('[%s]: %s', prefix, a:msg.Body.Name), line0] 56 | call writefile(lines, a:job.logfile, 'a') 57 | elseif g:OmniSharp_loglevel ==# 'DEBUG' && lines[0] =~# '^\*\{12\}' 58 | " Special loglevel - DEBUG all caps. This still tells the server to pass 59 | " full debugging requests and responses plus debugging messages, but 60 | " OmniSharp-vim will not log the requests and responses - just record 61 | " their commands 62 | let prefix = matchstr(lines[0], '\*\s\+\zs\S\+\ze\%(\s(.\{-})\)\?\s\+\*') 63 | let num_lines = len(lines) 64 | let commands = filter(lines, "v:val =~# '^\\s*\"Command\":'") 65 | if len(commands) 66 | let command = matchstr(commands[0], '"Command": "\zs[^"]\+\ze"') 67 | let command_name = printf('Server %s: %s (%d lines)', 68 | \ prefix, command, num_lines - 1) 69 | call writefile([command_name], a:job.logfile, 'a') 70 | endif 71 | else 72 | let lines[0] = ' ' . lines[0] 73 | let prefix = s:LogLevelPrefix(a:msg.Body.LogLevel) 74 | call insert(lines, printf('[%s]: %s', prefix, a:msg.Body.Name)) 75 | call writefile(lines, a:job.logfile, 'a') 76 | endif 77 | elseif get(a:msg, 'Event', '') ==# 'MsBuildProjectDiagnostics' 78 | if len(a:msg.Body.Errors) == 0 && len(a:msg.Body.Warnings) == 0 79 | return 80 | endif 81 | let lines = [a:msg.Body.FileName] 82 | for error in a:msg.Body.Errors 83 | call add(lines, printf('%s(%d,%d): Error: %s', 84 | \ error.FileName, error.StartLine, error.StartColumn, error.Text)) 85 | endfor 86 | for warn in a:msg.Body.Warnings 87 | call add(lines, printf('%s(%d,%d): Warning: %s', 88 | \ warn.FileName, warn.StartLine, warn.StartColumn, warn.Text)) 89 | endfor 90 | call writefile(lines, a:job.logfile, 'a') 91 | endif 92 | endfunction 93 | 94 | function! OmniSharp#log#Open(...) abort 95 | if g:OmniSharp_server_stdio 96 | let logfile = s:stdiologfile 97 | if exists('b:OmniSharp_host') 98 | let job = OmniSharp#GetHost().job 99 | if type(job) == type({}) 100 | let logfile = get(job, 'logfile', s:stdiologfile) 101 | endif 102 | endif 103 | else 104 | let logfile = OmniSharp#py#Eval('getLogFile()') 105 | if OmniSharp#py#CheckForError() | return | endif 106 | endif 107 | let cmd = (a:0 && type(a:1) == type('') && len(a:1)) ? a:1 : 'edit' 108 | if cmd ==# 'edit' && !&hidden 109 | let cmd = 'split' 110 | endif 111 | exec cmd logfile 112 | endfunction 113 | 114 | function! s:LogLevelPrefix(loglevel) abort 115 | if a:loglevel ==# 'TRACE' 116 | return 'trce' 117 | elseif a:loglevel ==# 'DEBUG' 118 | return 'dbug' 119 | elseif a:loglevel ==# 'INFORMATION' 120 | return 'info' 121 | elseif a:loglevel ==# 'WARNING' 122 | return 'warn' 123 | elseif a:loglevel ==# 'ERROR' 124 | return 'fail' 125 | elseif a:loglevel ==# 'CRITICAL' 126 | return 'crit' 127 | else 128 | return a:loglevel 129 | endif 130 | endfunction 131 | 132 | function! s:Init(job) abort 133 | if has_key(a:job, 'logfile') 134 | return 135 | endif 136 | let logfile = strftime('%Y%m%d%H%M_') . get(a:job, 'pid') . '_omnisharp.log' 137 | let logfile = fnamemodify(s:stdiologfile, ':h') . '/' . logfile 138 | " Add the new log filename to the standard log, so it can be opened with `gf` 139 | call writefile([logfile], s:stdiologfile, 'a') 140 | let a:job.logfile = logfile 141 | endfunction 142 | 143 | let &cpoptions = s:save_cpo 144 | unlet s:save_cpo 145 | 146 | " vim:et:sw=2:sts=2 147 | -------------------------------------------------------------------------------- /autoload/OmniSharp/preview.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#preview#Display(content, title) abort 5 | execute 'silent pedit' a:title 6 | silent wincmd P 7 | setlocal modifiable noreadonly 8 | setlocal nobuflisted buftype=nofile bufhidden=wipe 9 | 0,$d 10 | silent put =a:content 11 | 0d_ 12 | setfiletype omnisharpdoc 13 | setlocal conceallevel=3 14 | setlocal nomodifiable readonly 15 | let winid = winnr() 16 | silent wincmd p 17 | return winid 18 | endfunction 19 | 20 | function! OmniSharp#preview#File(filename, lnum, col) abort 21 | let lazyredraw_bak = &lazyredraw 22 | let &lazyredraw = 1 23 | " Due to cursor jumping bug, opening preview at current file is not as 24 | " simple as `pedit %`: 25 | " http://vim.1045645.n5.nabble.com/BUG-BufReadPre-autocmd-changes-cursor-position-on-pedit-td1206965.html 26 | let winview = winsaveview() 27 | let l:winnr = winnr() 28 | execute 'silent pedit' a:filename 29 | wincmd P 30 | call cursor(a:lnum, a:col) 31 | normal! zt 32 | if winnr() != l:winnr 33 | wincmd p 34 | " Jump cursor back to symbol. 35 | call winrestview(winview) 36 | endif 37 | let &lazyredraw = lazyredraw_bak 38 | endfunction 39 | 40 | let &cpoptions = s:save_cpo 41 | unlet s:save_cpo 42 | 43 | " vim:et:sw=2:sts=2 44 | -------------------------------------------------------------------------------- /autoload/OmniSharp/proc.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | let s:jobs = get(s:, 'jobs', {}) 5 | let s:channels = get(s:, 'channels', {}) 6 | 7 | " Neovim jobs {{{ " 8 | 9 | function! OmniSharp#proc#supportsNeovimJobs() abort 10 | return exists('*jobstart') 11 | endfunction 12 | 13 | function! OmniSharp#proc#neovimOutHandler(job_id, data, event) dict abort 14 | if get(g:, 'OmniSharp_proc_debug') 15 | echom printf('%s: %s', string(a:event), string(a:data)) 16 | endif 17 | if g:OmniSharp_server_stdio 18 | let job = s:channels[a:job_id] 19 | 20 | let messages = a:data[:-2] 21 | 22 | if len(a:data) > 1 23 | let messages[0] = job.partial . messages[0] 24 | let job.partial = a:data[-1] 25 | else 26 | let job.partial = job.partial . a:data[0] 27 | endif 28 | 29 | for message in messages 30 | if message =~# "^\uFEFF" 31 | " Strip BOM 32 | let message = substitute(message, "^\uFEFF", '', '') 33 | endif 34 | call OmniSharp#stdio#HandleResponse(job, message) 35 | endfor 36 | endif 37 | endfunction 38 | 39 | function! OmniSharp#proc#neovimErrHandler(job_id, data, event) dict abort 40 | if type(a:data) == type([]) && len(a:data) == 1 && a:data[0] =~# "^\uFEFF$" 41 | " Ignore BOM 42 | return 43 | endif 44 | if type(a:data) == type([]) && len(a:data) == 1 && a:data[0] ==# '' 45 | " Ignore empty 46 | return 47 | endif 48 | let message = printf('%s: %s', a:event, string(a:data)) 49 | call OmniSharp#util#EchoErr(message) 50 | endfunction 51 | 52 | function! OmniSharp#proc#neovimExitHandler(job_id, data, event) dict abort 53 | let jobkey = '' 54 | for [key, val] in items(s:jobs) 55 | if a:job_id == val.job_id 56 | let jobkey = key 57 | break 58 | endif 59 | endfor 60 | endfunction 61 | 62 | function! OmniSharp#proc#neovimJobStart(command) abort 63 | if !OmniSharp#proc#supportsNeovimJobs() 64 | call OmniSharp#util#EchoErr('Not using neovim') 65 | return -1 66 | endif 67 | call s:debug('Using Neovim jobstart to start the following command:') 68 | call s:debug(a:command) 69 | let opts = {'on_stderr': 'OmniSharp#proc#neovimErrHandler', 70 | \ 'on_exit': 'OmniSharp#proc#neovimExitHandler'} 71 | if g:OmniSharp_server_stdio || get(g:, 'OmniSharp_proc_debug') 72 | let opts['on_stdout'] = 'OmniSharp#proc#neovimOutHandler' 73 | endif 74 | let job = { 75 | \ 'start_time': reltime(), 76 | \ 'job_id': jobstart(a:command, opts), 77 | \ 'partial': '' 78 | \} 79 | let job.pid = jobpid(job.job_id) 80 | let s:channels[job.job_id] = job 81 | call OmniSharp#log#Log(job, split(execute('version'), "\n")[0]) 82 | return job 83 | endfunction 84 | 85 | " }}} Neovim jobs " 86 | 87 | " Vim jobs {{{ " 88 | 89 | function! OmniSharp#proc#supportsVimJobs() abort 90 | return exists('*job_start') 91 | endfunction 92 | 93 | function! OmniSharp#proc#vimOutHandler(channel, message) abort 94 | if get(g:, 'OmniSharp_proc_debug') 95 | echom printf('%s: %s', string(a:channel), string(a:message)) 96 | endif 97 | if g:OmniSharp_server_stdio 98 | let message = a:message 99 | if message =~# "^\uFEFF" 100 | " Strip BOM 101 | let message = substitute(message, "^\uFEFF", '', '') 102 | endif 103 | let job = s:channels[ch_info(a:channel).id] 104 | call OmniSharp#stdio#HandleResponse(job, message) 105 | endif 106 | endfunction 107 | 108 | function! OmniSharp#proc#vimErrHandler(channel, message) abort 109 | if ch_status(a:channel) ==# 'closed' 110 | return 111 | endif 112 | let message = printf('%s: %s', string(a:channel), string(a:message)) 113 | call OmniSharp#util#EchoErr(message) 114 | endfunction 115 | 116 | function! OmniSharp#proc#vimJobStart(command) abort 117 | if !OmniSharp#proc#supportsVimJobs() 118 | call OmniSharp#util#EchoErr('Not using Vim 8.0+') 119 | return -1 120 | endif 121 | call s:debug('Using vim job_start to start the following command:') 122 | call s:debug(a:command) 123 | let opts = {'err_cb': 'OmniSharp#proc#vimErrHandler'} 124 | if g:OmniSharp_server_stdio || get(g:, 'OmniSharp_proc_debug') 125 | let opts['out_cb'] = 'OmniSharp#proc#vimOutHandler' 126 | endif 127 | if has('patch-8.1.350') 128 | let opts.noblock = 1 129 | endif 130 | let job = { 131 | \ 'start_time': reltime(), 132 | \ 'job_id': job_start(a:command, opts) 133 | \} 134 | let job.pid = job_info(job.job_id).process 135 | let channel_id = ch_info(job_getchannel(job.job_id)).id 136 | let s:channels[channel_id] = job 137 | call OmniSharp#log#Log(job, join(split(execute('version'), "\n")[0:1], ', ')) 138 | return job 139 | endfunction 140 | 141 | " }}} Vim jobs " 142 | 143 | " vim-dispatch {{{ " 144 | 145 | function! OmniSharp#proc#supportsVimDispatch() abort 146 | return exists(':Dispatch') == 2 && !g:OmniSharp_server_stdio 147 | endfunction 148 | 149 | function! OmniSharp#proc#dispatchStart(command) abort 150 | if OmniSharp#proc#supportsVimDispatch() 151 | return dispatch#spawn( 152 | \ call('dispatch#shellescape', a:command), 153 | \ {'background': 1}) 154 | else 155 | call OmniSharp#util#EchoErr('vim-dispatch not found') 156 | return -1 157 | endif 158 | endfunction 159 | 160 | " }}} vim-dispatch " 161 | 162 | " vim-proc {{{ " 163 | 164 | function! OmniSharp#proc#supportsVimProc() abort 165 | if g:OmniSharp_server_stdio | return 0 | endif 166 | let is_vimproc = 0 167 | silent! let is_vimproc = vimproc#version() 168 | return is_vimproc 169 | endfunction 170 | 171 | function! OmniSharp#proc#vimprocStart(command) abort 172 | if OmniSharp#proc#supportsVimProc() 173 | return vimproc#popen3(a:command) 174 | else 175 | call OmniSharp#util#EchoErr('vimproc not found') 176 | return -1 177 | endif 178 | endfunction 179 | 180 | " }}} vim-proc " 181 | 182 | " public functions {{{ " 183 | 184 | function! OmniSharp#proc#Start(command, jobkey) abort 185 | if OmniSharp#proc#supportsNeovimJobs() 186 | let job = OmniSharp#proc#neovimJobStart(a:command) 187 | if job.job_id > 0 188 | let s:jobs[a:jobkey] = job 189 | else 190 | call OmniSharp#util#EchoErr('Command is not executable: ' . a:command[0]) 191 | endif 192 | elseif OmniSharp#proc#supportsVimJobs() 193 | let job = OmniSharp#proc#vimJobStart(a:command) 194 | if job_status(job.job_id) ==# 'run' 195 | let s:jobs[a:jobkey] = job 196 | else 197 | call OmniSharp#util#EchoErr('Could not run command: ' . join(a:command)) 198 | endif 199 | elseif OmniSharp#proc#supportsVimDispatch() 200 | let job = OmniSharp#proc#dispatchStart(a:command) 201 | let s:jobs[a:jobkey] = job 202 | elseif OmniSharp#proc#supportsVimProc() 203 | let job = OmniSharp#proc#vimprocStart(a:command) 204 | let s:jobs[a:jobkey] = job 205 | else 206 | call OmniSharp#util#EchoErr( 207 | \ 'Please use neovim, or vim 8.0+ or install either vim-dispatch or ' . 208 | \ 'vimproc.vim plugin to use this feature') 209 | endif 210 | if type(job) == type({}) 211 | let job.sln_or_dir = a:jobkey 212 | let job.loaded = 0 213 | call OmniSharp#log#Log(job, '') 214 | call OmniSharp#log#Log(job, 'OmniSharp server started.') 215 | call OmniSharp#log#Log(job, ' Path: ' . OmniSharp#util#GetServerPath()) 216 | call OmniSharp#log#Log(job, ' Target: ' . a:jobkey) 217 | call OmniSharp#log#Log(job, ' PID: ' . job.pid) 218 | call OmniSharp#log#Log(job, ' Command: ' . join(a:command), 1) 219 | call OmniSharp#log#Log(job, '') 220 | silent doautocmd User OmniSharpStarted 221 | endif 222 | return job 223 | endfunction 224 | 225 | function! OmniSharp#proc#StopJob(jobkey) abort 226 | if !OmniSharp#proc#IsJobRunning(a:jobkey) 227 | return 228 | endif 229 | let job = s:jobs[a:jobkey] 230 | let job.stopping = 1 231 | 232 | if OmniSharp#proc#supportsNeovimJobs() 233 | call jobstop(job.job_id) 234 | elseif OmniSharp#proc#supportsVimJobs() 235 | call job_stop(job.job_id) 236 | elseif OmniSharp#proc#supportsVimDispatch() 237 | call dispatch#abort_command(0, job.command) 238 | elseif OmniSharp#proc#supportsVimProc() 239 | call job.kill() 240 | endif 241 | let job.stopped = 1 242 | silent doautocmd User OmniSharpStopped 243 | endfunction 244 | 245 | function! OmniSharp#proc#ListJobs() abort 246 | return keys(s:jobs) 247 | endfunction 248 | 249 | function! OmniSharp#proc#ListRunningJobs() abort 250 | return filter(keys(s:jobs), 'OmniSharp#proc#IsJobRunning(v:val)') 251 | endfunction 252 | 253 | function! OmniSharp#proc#IsJobRunning(jobkey) abort 254 | " Either a jobkey (sln_or_dir) or a job may be passed in 255 | if type(a:jobkey) == type({}) 256 | let job = a:jobkey 257 | else 258 | if !has_key(s:jobs, a:jobkey) 259 | return 0 260 | endif 261 | let job = get(s:jobs, a:jobkey) 262 | endif 263 | if OmniSharp#proc#supportsNeovimJobs() 264 | return !(get(job, 'stopped', 0) || get(job, 'stopping', 0)) 265 | elseif OmniSharp#proc#supportsVimJobs() 266 | let status = job_status(job.job_id) 267 | return status ==# 'run' && !(get(job, 'stopped', 0) || get(job, 'stopping', 0)) 268 | elseif OmniSharp#proc#supportsVimDispatch() 269 | return dispatch#completed(job) 270 | elseif OmniSharp#proc#supportsVimProc() 271 | let [cond, status] = job.checkpid() 272 | return status != 0 273 | endif 274 | endfunction 275 | 276 | function! OmniSharp#proc#GetJob(jobkey) abort 277 | return get(s:jobs, a:jobkey, '') 278 | endfunction 279 | 280 | " }}} public functions " 281 | 282 | " private functions {{{ " 283 | 284 | function! s:debug(message) abort 285 | if get(g:, 'OmniSharp_proc_debug') 286 | echom 'DEBUG: ' . string(a:message) 287 | endif 288 | endfunction 289 | 290 | " }}} private functions " 291 | 292 | let &cpoptions = s:save_cpo 293 | unlet s:save_cpo 294 | 295 | " vim:et:sw=2:sts=2 296 | -------------------------------------------------------------------------------- /autoload/OmniSharp/project.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpoptions 2 | set cpoptions&vim 3 | 4 | function! OmniSharp#project#CountLoaded() abort 5 | if !g:OmniSharp_server_stdio | return 0 | endif 6 | let host = OmniSharp#GetHost() 7 | return get(OmniSharp#proc#GetJob(host.sln_or_dir), 'projects_loaded', 0) 8 | endfunction 9 | 10 | function! OmniSharp#project#CountTotal() abort 11 | if !g:OmniSharp_server_stdio | return 0 | endif 12 | let host = OmniSharp#GetHost() 13 | return get(OmniSharp#proc#GetJob(host.sln_or_dir), 'projects_total', 0) 14 | endfunction 15 | 16 | function! OmniSharp#project#RegisterLoaded(job) abort 17 | if a:job.loaded | return | endif 18 | if g:OmniSharp_server_display_loading 19 | if has_key(a:job, 'restart_time') 20 | let elapsed = reltimefloat(reltime(a:job.restart_time)) 21 | echomsg printf('Reloaded %s in %.1fs', 22 | \ a:job.restart_project, elapsed) 23 | unlet a:job.restart_time 24 | unlet a:job.restart_project 25 | else 26 | let elapsed = reltimefloat(reltime(a:job.start_time)) 27 | echomsg printf('Loaded server for %s in %.1fs', 28 | \ a:job.sln_or_dir, elapsed) 29 | endif 30 | endif 31 | let a:job.loaded = 1 32 | silent doautocmd User OmniSharpReady 33 | call OmniSharp#log#Log(a:job, 'All projects loaded') 34 | " If any requests are waiting to be replayed after the server is loaded, 35 | " replay them now. 36 | " 37 | " TODO: If we start listening for individual project load status, then do 38 | " this when this project finishes loading, instead of when the entire 39 | " solution finishes loading. 40 | " 41 | " Remove this 1s delay if/when we get better project-laoded information 42 | " - currently we don't get any better indicators from the server. 43 | call timer_start(1000, function('OmniSharp#stdio#ReplayOnLoad', [a:job])) 44 | endfunction 45 | 46 | " Listen for stdio server-loaded events 47 | function! OmniSharp#project#ParseEvent(job, event, eventBody) abort 48 | " Full load: Wait for all projects to load before marking server as ready 49 | let projects_loaded = get(a:job, 'projects_loaded', 0) 50 | let projects_total = get(a:job, 'projects_total', 0) 51 | if a:job.loaded && projects_loaded == projects_total | return | endif 52 | 53 | if !has_key(a:job, 'loading_timeout') 54 | " Create a timeout to mark a job as loaded after 180 seconds despite not 55 | " receiving the expected server events. 56 | let a:job.loading_timeout = timer_start( 57 | \ g:OmniSharp_server_loading_timeout * 1000, 58 | \ function('s:ServerLoadTimeout', [a:job])) 59 | endif 60 | if !has_key(a:job, 'loading') 61 | let a:job.loading = [] 62 | endif 63 | let name = get(a:eventBody, 'Name', '') 64 | let message = get(a:eventBody, 'Message', '') 65 | if a:event ==# 'started' 66 | call OmniSharp#actions#workspace#Get(a:job) 67 | elseif name ==# 'OmniSharp.MSBuild.ProjectManager' 68 | let project = matchstr(message, '''\zs.*\ze''') 69 | if message =~# '^Queue project' 70 | call add(a:job.loading, project) 71 | if len(a:job.loading) > projects_total 72 | let a:job.projects_total = len(a:job.loading) 73 | silent doautocmd User OmniSharpProjectUpdated 74 | endif 75 | endif 76 | if message =~# '^Successfully loaded project' 77 | \ || message =~# '^Failed to load project' 78 | if message[0] ==# 'F' 79 | echom 'Failed to load project: ' . project 80 | endif 81 | call filter(a:job.loading, {idx,val -> val !=# project}) 82 | let a:job.projects_loaded = projects_loaded + 1 83 | silent doautocmd User OmniSharpProjectUpdated 84 | if len(a:job.loading) == 0 85 | call OmniSharp#project#RegisterLoaded(a:job) 86 | unlet a:job.loading 87 | call timer_stop(a:job.loading_timeout) 88 | unlet a:job.loading_timeout 89 | endif 90 | endif 91 | endif 92 | endfunction 93 | 94 | function! s:ServerLoadTimeout(job, timer) abort 95 | if g:OmniSharp_server_display_loading 96 | echomsg printf('Server load notification for %s not received after %d seconds - continuing.', 97 | \ a:job.sln_or_dir, g:OmniSharp_server_loading_timeout) 98 | endif 99 | let a:job.loaded = 1 100 | unlet a:job.loading 101 | unlet a:job.loading_timeout 102 | silent doautocmd User OmniSharpReady 103 | endfunction 104 | 105 | let &cpoptions = s:save_cpo 106 | unlet s:save_cpo 107 | 108 | " vim:et:sw=2:sts=2 109 | -------------------------------------------------------------------------------- /autoload/OmniSharp/py.vim: -------------------------------------------------------------------------------- 1 | if !(has('python') || has('python3')) 2 | finish 3 | endif 4 | 5 | let s:save_cpo = &cpoptions 6 | set cpoptions&vim 7 | 8 | let s:alive_cache = get(s:, 'alive_cache', []) 9 | let s:pycmd = has('python3') ? 'python3' : 'python' 10 | let s:pyfile = has('python3') ? 'py3file' : 'pyfile' 11 | let g:OmniSharp_py_err = {} 12 | let g:OmniSharp_python_path = OmniSharp#util#PathJoin(['python']) 13 | 14 | " Default map of solution files and directories to ports. 15 | " Preserve backwards compatibility with older version g:OmniSharp_sln_ports 16 | let g:OmniSharp_server_ports = get(g:, 'OmniSharp_server_ports', get(g:, 'OmniSharp_sln_ports', {})) 17 | let s:initial_server_ports = get(s:, 'initial_server_ports', 18 | \ copy(g:OmniSharp_server_ports)) 19 | 20 | if has('python3') && exists('*py3eval') 21 | let s:pyeval = function('py3eval') 22 | elseif exists('*pyeval') 23 | let s:pyeval = function('pyeval') 24 | else 25 | exec s:pycmd 'import json, vim' 26 | function! s:pyeval(e) 27 | exec s:pycmd 'vim.command("return " + json.dumps(eval(vim.eval("a:e"))))' 28 | endfunction 29 | endif 30 | 31 | function! OmniSharp#py#Bootstrap() abort 32 | if exists('s:bootstrap_complete') | return | endif 33 | exec s:pycmd "sys.path.append(r'" . g:OmniSharp_python_path . "')" 34 | exec s:pyfile fnameescape(OmniSharp#util#PathJoin(['python', 'bootstrap.py'])) 35 | let s:bootstrap_complete = 1 36 | endfunction 37 | 38 | function! OmniSharp#py#CheckAlive(sln_or_dir) abort 39 | if index(s:alive_cache, a:sln_or_dir) >= 0 | return 1 | endif 40 | let alive = OmniSharp#py#Eval('checkAliveStatus()') 41 | if OmniSharp#py#CheckForError() | return 0 | endif 42 | if alive 43 | " Cache the alive status so subsequent calls are faster 44 | call add(s:alive_cache, a:sln_or_dir) 45 | endif 46 | return alive 47 | endfunction 48 | 49 | function! OmniSharp#py#CheckForError(...) abort 50 | let should_print = a:0 ? a:1 : 1 51 | if !empty(g:OmniSharp_py_err) 52 | if should_print 53 | call OmniSharp#util#EchoErr( 54 | \ printf('%s: %s', g:OmniSharp_py_err.code, g:OmniSharp_py_err.msg)) 55 | endif 56 | " If we got a connection error when hitting the server, then the server may 57 | " not be running anymore and we should bust the 'alive' cache 58 | if g:OmniSharp_py_err.code ==? 'CONNECTION' 59 | call OmniSharp#py#Uncache() 60 | endif 61 | return 1 62 | endif 63 | return 0 64 | endfunction 65 | 66 | function! OmniSharp#py#FindRunningServer(solution_files) abort 67 | let running_slns = [] 68 | if len(g:OmniSharp_server_ports) 69 | " g:OmniSharp_server_ports has been set; auto-select one of the 70 | " specified servers 71 | for solutionfile in a:solution_files 72 | if has_key(g:OmniSharp_server_ports, solutionfile) 73 | call add(running_slns, solutionfile) 74 | endif 75 | endfor 76 | endif 77 | return running_slns 78 | endfunction 79 | 80 | function! OmniSharp#py#GetPort(...) abort 81 | if exists('g:OmniSharp_port') 82 | return g:OmniSharp_port 83 | endif 84 | 85 | let sln_or_dir = a:0 ? a:1 : OmniSharp#FindSolutionOrDir() 86 | if empty(sln_or_dir) 87 | return 0 88 | endif 89 | 90 | " If we're already running this solution, choose the port we're running on 91 | if has_key(g:OmniSharp_server_ports, sln_or_dir) 92 | return g:OmniSharp_server_ports[sln_or_dir] 93 | endif 94 | 95 | " Otherwise, find a free port and use that for this solution 96 | let port = OmniSharp#py#Eval('find_free_port()') 97 | if OmniSharp#py#CheckForError() | return 0 | endif 98 | let g:OmniSharp_server_ports[sln_or_dir] = port 99 | return port 100 | endfunction 101 | 102 | 103 | function! OmniSharp#py#Eval(cmd) abort 104 | return s:pyeval(a:cmd) 105 | endfunction 106 | 107 | function! OmniSharp#py#IsServerPortHardcoded(sln_or_dir) abort 108 | if exists('g:OmniSharp_port') | return 1 | endif 109 | return has_key(s:initial_server_ports, a:sln_or_dir) 110 | endfunction 111 | 112 | " Remove a server from the alive_cache 113 | function! OmniSharp#py#Uncache(...) abort 114 | let sln_or_dir = a:0 ? a:1 : OmniSharp#FindSolutionOrDir(0) 115 | let idx = index(s:alive_cache, sln_or_dir) 116 | if idx != -1 117 | call remove(s:alive_cache, idx) 118 | endif 119 | endfunction 120 | 121 | let &cpoptions = s:save_cpo 122 | unlet s:save_cpo 123 | 124 | " vim:et:sw=2:sts=2 125 | -------------------------------------------------------------------------------- /autoload/ale/sources/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | function! ale#sources#OmniSharp#WantResults() abort 2 | if !g:OmniSharp_server_stdio | return | endif 3 | let bufnr = g:ale_want_results_buffer 4 | if getbufvar(bufnr, '&filetype') !=# 'cs' | return | endif 5 | if !OmniSharp#buffer#Valid(bufnr) | return | endif 6 | let g:OmniSharp_diagnostics_requested = 1 7 | call ale#other_source#StartChecking(bufnr, 'OmniSharp') 8 | let opts = { 'BufNum': bufnr } 9 | let Callback = function('ale#sources#OmniSharp#ProcessResults', [opts]) 10 | call OmniSharp#actions#diagnostics#StdioCheck(bufnr, Callback) 11 | endfunction 12 | 13 | function! ale#sources#OmniSharp#ProcessResults(opts, locations) abort 14 | if getbufvar(a:opts.BufNum, 'OmniSharp_debounce_diagnostics', 0) 15 | call timer_stop(getbufvar(a:opts.BufNum, 'OmniSharp_debounce_diagnostics')) 16 | endif 17 | call setbufvar(a:opts.BufNum, 'OmniSharp_debounce_diagnostics', 18 | \ timer_start(200, function('s:ProcessResults', [a:opts, a:locations]))) 19 | endfunction 20 | 21 | function! s:ProcessResults(opts, locations, timer) abort 22 | for location in a:locations 23 | " Use case-insensitive comparison ==? 24 | if get(location, 'subtype', '') ==? 'style' 25 | let location['sub_type'] = 'style' 26 | endif 27 | endfor 28 | try 29 | call ale#other_source#ShowResults(a:opts.BufNum, 'OmniSharp', a:locations) 30 | catch 31 | " When many diagnostic requests are sent or unsolicited diagnostics received 32 | " (with EnableAnalyzerSupport) during editing, obsolete diagnostics can be 33 | " sent to ALE, which will result in errors. 34 | endtry 35 | endfunction 36 | 37 | " vim:et:sw=2:sts=2 38 | -------------------------------------------------------------------------------- /autoload/asyncomplete/sources/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | function! asyncomplete#sources#OmniSharp#completor(opt, ctx) abort 2 | let column = a:ctx['col'] 3 | let typed = a:ctx['typed'] 4 | 5 | let kw = matchstr(typed, '\(\w*\W\)*\zs\w\+$') 6 | let kwlen = len(kw) 7 | 8 | let startcol = column - kwlen 9 | 10 | let opts = { 11 | \ 'startcol': startcol - 1, 12 | \ 'Callback': {results-> 13 | \ asyncomplete#complete(a:opt['name'], a:ctx, startcol, results)} 14 | \} 15 | call OmniSharp#actions#complete#Get(kw, opts) 16 | endfunction 17 | 18 | " vim:et:sw=2:sts=2 19 | -------------------------------------------------------------------------------- /autoload/clap/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | if !OmniSharp#util#CheckCapabilities() | finish | endif 2 | 3 | let s:save_cpo = &cpoptions 4 | set cpoptions&vim 5 | 6 | function! s:format_line(quickfix) abort 7 | return printf('%s: %d col %d %s', 8 | \ a:quickfix.filename, a:quickfix.lnum, a:quickfix.col, a:quickfix.text) 9 | endfunction 10 | 11 | function! s:location_sink(str) abort 12 | for quickfix in s:quickfixes 13 | if s:format_line(quickfix) == a:str 14 | break 15 | endif 16 | endfor 17 | echo quickfix.filename 18 | call OmniSharp#locations#Navigate(quickfix) 19 | endfunction 20 | 21 | function! s:symbols_source() abort 22 | return map(copy(s:quickfixes), 's:format_line(v:val)') 23 | endfunction 24 | 25 | function! clap#OmniSharp#FindSymbols(quickfixes) abort 26 | let s:quickfixes = a:quickfixes 27 | Clap symbols 28 | endfunction 29 | 30 | let g:clap_provider_symbols = { 31 | \ 'source': function('s:symbols_source'), 32 | \ 'sink': function('s:location_sink') 33 | \} 34 | 35 | function! s:action_sink(str) abort 36 | if s:match_on_prefix 37 | let index = str2nr(a:str[0: stridx(a:str, ':') - 1]) 38 | let action = s:actions[index] 39 | else 40 | let filtered = filter(s:actions, {i,v -> get(v, 'Name') ==# a:str}) 41 | if len(filtered) == 0 42 | echomsg 'No action taken: ' . a:str 43 | return 44 | endif 45 | let action = filtered[0] 46 | endif 47 | if g:OmniSharp_server_stdio 48 | call OmniSharp#actions#codeactions#Run(action) 49 | else 50 | let command = substitute(get(action, 'Identifier'), '''', '\\''', 'g') 51 | let command = printf('runCodeAction(''%s'', ''%s'')', s:mode, command) 52 | let result = OmniSharp#py#Eval(command) 53 | if OmniSharp#py#CheckForError() | return | endif 54 | if !result 55 | echo 'No action taken' 56 | endif 57 | endif 58 | endfunction 59 | 60 | function! s:actions_source() abort 61 | let s:match_on_prefix = 0 62 | 63 | if has('win32') 64 | " Check whether any actions contain non-ascii characters. These are not 65 | " reliably passed to FZF and back, so rather than matching on the action 66 | " name, an index will be prefixed and the selected action will be selected 67 | " by prefix instead. 68 | for action in s:actions 69 | if action.Name =~# '[^\x00-\x7F]' 70 | let s:match_on_prefix = 1 71 | break 72 | endif 73 | endfor 74 | if s:match_on_prefix 75 | call map(s:actions, {i,v -> extend(v, {'Name': i . ': ' . v.Name})}) 76 | endif 77 | endif 78 | 79 | return map(copy(s:actions), 'v:val.Name') 80 | endfunction 81 | 82 | function! clap#OmniSharp#GetCodeActions(mode, actions) abort 83 | let s:actions = a:actions 84 | let s:mode = a:mode 85 | Clap actions 86 | endfunction 87 | 88 | let g:clap_provider_actions = { 89 | \ 'source': function('s:actions_source'), 90 | \ 'sink': function('s:action_sink') 91 | \} 92 | 93 | function! s:usages_source() abort 94 | return map(copy(s:quickfixes), 's:format_line(v:val)') 95 | endfunction 96 | 97 | function! clap#OmniSharp#FindUsages(quickfixes, target) abort 98 | let s:quickfixes = a:quickfixes 99 | Clap usages 100 | endfunction 101 | 102 | let g:clap_provider_usages = { 103 | \ 'source': function('s:usages_source'), 104 | \ 'sink': function('s:location_sink') 105 | \} 106 | 107 | " vim:et:sw=2:sts=2 108 | -------------------------------------------------------------------------------- /autoload/coc/source/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | function! coc#source#OmniSharp#init() abort 2 | return { 3 | \ 'shortcut': 'OS', 4 | \ 'filetypes': ['cs'], 5 | \ 'triggerCharacters': ['.'] 6 | \ } 7 | endfunction 8 | 9 | function! coc#source#OmniSharp#complete(options, callback) abort 10 | let opts = { 'Callback': a:callback } 11 | call OmniSharp#actions#complete#Get(a:options.input, opts) 12 | endfunction 13 | 14 | " vim:et:sw=2:sts=2 15 | -------------------------------------------------------------------------------- /autoload/ctrlp/OmniSharp/findcodeactions.vim: -------------------------------------------------------------------------------- 1 | if !OmniSharp#util#CheckCapabilities() | finish | endif 2 | if get(g:, 'loaded_ctrlp_OmniSharp_findcodeactions') | finish | endif 3 | let g:loaded_ctrlp_OmniSharp_findcodeactions = 1 4 | 5 | " Add this extension's settings to g:ctrlp_ext_vars 6 | " 7 | " Required: 8 | " 9 | " + init: the name of the input function including the brackets and any 10 | " arguments 11 | " 12 | " + accept: the name of the action function (only the name) 13 | " 14 | " + lname & sname: the long and short names to use for the statusline 15 | " 16 | " + type: the matching type 17 | " - line : match full line 18 | " - path : match full line like a file or a directory path 19 | " - tabs : match until first tab character 20 | " - tabe : match until last tab character 21 | " 22 | " Optional: 23 | " 24 | " + enter: the name of the function to be called before starting ctrlp 25 | " 26 | " + exit: the name of the function to be called after closing ctrlp 27 | " 28 | " + opts: the name of the option handling function called when initialize 29 | " 30 | " + sort: disable sorting (enabled by default when omitted) 31 | " 32 | " + specinput: enable special inputs '..' and '@cd' (disabled by default) 33 | " 34 | call add(g:ctrlp_ext_vars, { 35 | \ 'init': 'ctrlp#OmniSharp#findcodeactions#init()', 36 | \ 'accept': 'ctrlp#OmniSharp#findcodeactions#accept', 37 | \ 'lname': 'Find Code Actions', 38 | \ 'sname': 'code actions', 39 | \ 'type': 'line', 40 | \ 'sort': 1, 41 | \ 'nolim': 1, 42 | \ }) 43 | 44 | 45 | function! ctrlp#OmniSharp#findcodeactions#setactions(mode, actions) abort 46 | let s:actions = a:actions 47 | let s:mode = a:mode 48 | endfunction 49 | 50 | " Provide a list of strings to search in 51 | " 52 | " Return: a Vim's List 53 | " 54 | function! ctrlp#OmniSharp#findcodeactions#init() abort 55 | return map(copy(s:actions), {i,v -> get(v, 'Name')}) 56 | endfunction 57 | 58 | 59 | " The action to perform on the selected string 60 | " 61 | " Arguments: 62 | " a:mode the mode that has been chosen by pressing or 63 | " the values are 'e', 'v', 't' and 'h', respectively 64 | " a:str the selected string 65 | " 66 | function! ctrlp#OmniSharp#findcodeactions#accept(mode, str) abort 67 | call ctrlp#exit() 68 | let action = filter(copy(s:actions), {i,v -> get(v, 'Name') ==# a:str})[0] 69 | if g:OmniSharp_server_stdio 70 | call OmniSharp#actions#codeactions#Run(action) 71 | else 72 | let command = substitute(get(action, 'Identifier'), '''', '\\''', 'g') 73 | let command = printf('runCodeAction(''%s'', ''%s'')', s:mode, command) 74 | let result = OmniSharp#py#Eval(command) 75 | if OmniSharp#py#CheckForError() | return | endif 76 | if !result 77 | echo 'No action taken' 78 | endif 79 | endif 80 | endfunction 81 | 82 | " Give the extension an ID 83 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 84 | 85 | " Allow it to be called later 86 | function! ctrlp#OmniSharp#findcodeactions#id() abort 87 | return s:id 88 | endfunction 89 | 90 | " vim:et:sw=2:sts=2 91 | -------------------------------------------------------------------------------- /autoload/ctrlp/OmniSharp/findsymbols.vim: -------------------------------------------------------------------------------- 1 | if !OmniSharp#util#CheckCapabilities() | finish | endif 2 | if get(g:, 'loaded_ctrlp_OmniSharp_findsymbols') | finish | endif 3 | let g:loaded_ctrlp_OmniSharp_findsymbols = 1 4 | 5 | " Add this extension's settings to g:ctrlp_ext_vars 6 | " 7 | " Required: 8 | " 9 | " + init: the name of the input function including the brackets and any 10 | " arguments 11 | " 12 | " + accept: the name of the action function (only the name) 13 | " 14 | " + lname & sname: the long and short names to use for the statusline 15 | " 16 | " + type: the matching type 17 | " - line : match full line 18 | " - path : match full line like a file or a directory path 19 | " - tabs : match until first tab character 20 | " - tabe : match until last tab character 21 | " 22 | " Optional: 23 | " 24 | " + enter: the name of the function to be called before starting ctrlp 25 | " 26 | " + exit: the name of the function to be called after closing ctrlp 27 | " 28 | " + opts: the name of the option handling function called when initialize 29 | " 30 | " + sort: disable sorting (enabled by default when omitted) 31 | " 32 | " + specinput: enable special inputs '..' and '@cd' (disabled by default) 33 | " 34 | call add(g:ctrlp_ext_vars, { 35 | \ 'init': 'ctrlp#OmniSharp#findsymbols#init()', 36 | \ 'accept': 'ctrlp#OmniSharp#findsymbols#accept', 37 | \ 'lname': 'Find Symbols', 38 | \ 'sname': 'symbols', 39 | \ 'type': 'tabs', 40 | \ 'sort': 1, 41 | \ 'nolim': 1, 42 | \ }) 43 | 44 | 45 | function! ctrlp#OmniSharp#findsymbols#setsymbols(quickfixes) abort 46 | let s:quickfixes = a:quickfixes 47 | let s:symbols = [] 48 | for quickfix in s:quickfixes 49 | call add(s:symbols, quickfix.text) 50 | endfor 51 | endfunction 52 | 53 | " Provide a list of strings to search in 54 | " 55 | " Return: a Vim's List 56 | " 57 | function! ctrlp#OmniSharp#findsymbols#init() abort 58 | return s:symbols 59 | endfunction 60 | 61 | 62 | " The action to perform on the selected string 63 | " 64 | " Arguments: 65 | " a:mode the mode that has been chosen by pressing or 66 | " the values are 'e', 'v', 't' and 'h', respectively 67 | " a:str the selected string 68 | " 69 | function! ctrlp#OmniSharp#findsymbols#accept(mode, str) abort 70 | call ctrlp#exit() 71 | for quickfix in s:quickfixes 72 | if quickfix.text == a:str 73 | break 74 | endif 75 | endfor 76 | echo quickfix.filename 77 | call OmniSharp#locations#Navigate(quickfix) 78 | endfunction 79 | 80 | " Give the extension an ID 81 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 82 | 83 | " Allow it to be called later 84 | function! ctrlp#OmniSharp#findsymbols#id() abort 85 | return s:id 86 | endfunction 87 | 88 | " vim:et:sw=2:sts=2 89 | -------------------------------------------------------------------------------- /autoload/deoplete/source/omnisharp.vim: -------------------------------------------------------------------------------- 1 | let s:currentLhsRequest = v:null 2 | 3 | function! s:onReceivedResponse(lhs, results) abort 4 | if s:currentLhsRequest != a:lhs 5 | return 6 | endif 7 | 8 | let g:deoplete#source#omnisharp#_results = a:results 9 | call deoplete#auto_complete() 10 | endfunction 11 | 12 | function! deoplete#source#omnisharp#sendRequest(lhs, partial) abort 13 | let s:currentLhsRequest = a:lhs 14 | let g:deoplete#source#omnisharp#_results = v:null 15 | let opts = { 16 | \ 'Callback': {results -> s:onReceivedResponse(a:lhs, results)} 17 | \} 18 | call OmniSharp#actions#complete#Get(a:partial, opts) 19 | endfunction 20 | -------------------------------------------------------------------------------- /autoload/fzf/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | if !OmniSharp#util#CheckCapabilities() | finish | endif 2 | 3 | let s:save_cpo = &cpoptions 4 | set cpoptions&vim 5 | 6 | function! s:format_line(quickfix) abort 7 | return printf('%s: %d col %d %s', 8 | \ a:quickfix.filename, a:quickfix.lnum, a:quickfix.col, a:quickfix.text) 9 | endfunction 10 | 11 | function! s:location_sink(str) abort 12 | for quickfix in s:quickfixes 13 | if s:format_line(quickfix) == a:str 14 | break 15 | endif 16 | endfor 17 | echo quickfix.filename 18 | call OmniSharp#locations#Navigate(quickfix) 19 | endfunction 20 | 21 | function! fzf#OmniSharp#FindSymbols(quickfixes) abort 22 | let s:quickfixes = a:quickfixes 23 | let symbols = [] 24 | for quickfix in s:quickfixes 25 | call add(symbols, s:format_line(quickfix)) 26 | endfor 27 | let fzf_options = copy(get(g:, 'OmniSharp_fzf_options', { 'down': '40%' })) 28 | call fzf#run( 29 | \ extend(fzf_options, { 30 | \ 'source': symbols, 31 | \ 'sink': function('s:location_sink')})) 32 | endfunction 33 | 34 | function! s:action_sink(str) abort 35 | if s:match_on_prefix 36 | let index = str2nr(a:str[0: stridx(a:str, ':') - 1]) 37 | let action = s:actions[index] 38 | else 39 | let filtered = filter(s:actions, {i,v -> get(v, 'Name') ==# a:str}) 40 | if len(filtered) == 0 41 | echomsg 'No action taken: ' . a:str 42 | return 43 | endif 44 | let action = filtered[0] 45 | endif 46 | if g:OmniSharp_server_stdio 47 | call OmniSharp#actions#codeactions#Run(action) 48 | else 49 | let command = substitute(get(action, 'Identifier'), '''', '\\''', 'g') 50 | let command = printf('runCodeAction(''%s'', ''%s'')', s:mode, command) 51 | let result = OmniSharp#py#Eval(command) 52 | if OmniSharp#py#CheckForError() | return | endif 53 | if !result 54 | echo 'No action taken' 55 | endif 56 | endif 57 | endfunction 58 | 59 | function! fzf#OmniSharp#GetCodeActions(mode, actions) abort 60 | let s:match_on_prefix = 0 61 | let s:actions = a:actions 62 | 63 | if has('win32') 64 | " Check whether any actions contain non-ascii characters. These are not 65 | " reliably passed to FZF and back, so rather than matching on the action 66 | " name, an index will be prefixed and the selected action will be selected 67 | " by prefix instead. 68 | for action in s:actions 69 | if action.Name =~# '[^\x00-\x7F]' 70 | let s:match_on_prefix = 1 71 | break 72 | endif 73 | endfor 74 | if s:match_on_prefix 75 | call map(s:actions, {i,v -> extend(v, {'Name': i . ': ' . v.Name})}) 76 | endif 77 | endif 78 | 79 | let s:mode = a:mode 80 | let actionNames = map(copy(s:actions), 'v:val.Name') 81 | 82 | let fzf_options = copy(get(g:, 'OmniSharp_fzf_options', { 'down': '10%' })) 83 | call fzf#run( 84 | \ extend(fzf_options, { 85 | \ 'source': actionNames, 86 | \ 'sink': function('s:action_sink')})) 87 | endfunction 88 | 89 | function! fzf#OmniSharp#FindUsages(quickfixes, target) abort 90 | let s:quickfixes = a:quickfixes 91 | let usages = [] 92 | for quickfix in s:quickfixes 93 | call add(usages, s:format_line(quickfix)) 94 | endfor 95 | let fzf_options = copy(get(g:, 'OmniSharp_fzf_options', { 'down': '40%' })) 96 | call fzf#run(fzf#wrap( 97 | \ extend(fzf_options, { 98 | \ 'source': usages, 99 | \ 'sink': function('s:location_sink')}))) 100 | endfunction 101 | 102 | function! fzf#OmniSharp#FindMembers(quickfixes, target) abort 103 | let s:quickfixes = a:quickfixes 104 | let usages = [] 105 | for quickfix in s:quickfixes 106 | call add(usages, s:format_line(quickfix)) 107 | endfor 108 | let fzf_options = copy(get(g:, 'OmniSharp_fzf_options', { 'down': '40%' })) 109 | call fzf#run(fzf#wrap( 110 | \ extend(fzf_options, { 111 | \ 'source': usages, 112 | \ 'sink': function('s:location_sink')}))) 113 | endfunction 114 | 115 | " vim:et:sw=2:sts=2 116 | -------------------------------------------------------------------------------- /autoload/ncm2/sources/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | if get(s:, 'loaded') 2 | finish 3 | endif 4 | let s:loaded = 1 5 | 6 | function! ncm2#sources#OmniSharp#on_complete(ctx) abort 7 | let kw = matchstr(a:ctx['typed'], '\(\w*\W\)*\zs\w\+$') 8 | let opts = { 9 | \ 'Callback': {results -> ncm2#complete(a:ctx, a:ctx['startccol'], results)} 10 | \} 11 | call OmniSharp#actions#complete#Get(kw, opts) 12 | endfunction 13 | 14 | " vim:et:sw=2:sts=2 15 | -------------------------------------------------------------------------------- /autoload/unite/sources/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | if !OmniSharp#util#CheckCapabilities() | finish | endif 2 | 3 | let s:save_cpo = &cpoptions 4 | set cpoptions&vim 5 | 6 | let s:findcodeactions = { 7 | \ 'name': 'OmniSharp/findcodeactions', 8 | \ 'description': 'candidates from code actions of OmniSharp', 9 | \ 'default_action': 'run', 10 | \ 'is_listed': 0, 11 | \ } 12 | 13 | function! s:findcodeactions.gather_candidates(args, context) abort 14 | let s:mode = get(a:args, 0, 'normal') 15 | let s:actions = get(a:args, 1, []) 16 | 17 | let actions = map(copy(s:actions), {i,v -> get(v, 'Name')}) 18 | return map(actions, '{ 19 | \ "word": v:val, 20 | \ "source__OmniSharp_action": v:val, 21 | \ }') 22 | endfunction 23 | 24 | let s:findcodeactions_action_table = { 25 | \ 'run': { 26 | \ 'description': 'run action', 27 | \ } 28 | \ } 29 | function! s:findcodeactions_action_table.run.func(candidate) abort 30 | let str = a:candidate.source__OmniSharp_action 31 | 32 | let action = filter(copy(s:actions), {i,v -> get(v, 'Name') ==# str})[0] 33 | if g:OmniSharp_server_stdio 34 | call OmniSharp#actions#codeactions#Run(action) 35 | else 36 | let command = substitute(get(action, 'Identifier'), '''', '\\''', 'g') 37 | let command = printf('runCodeAction(''%s'', ''%s'')', s:mode, command) 38 | let result = OmniSharp#py#Eval(command) 39 | if OmniSharp#py#CheckForError() | return | endif 40 | if !result 41 | echo 'No action taken' 42 | endif 43 | endif 44 | endfunction 45 | let s:findcodeactions.action_table = s:findcodeactions_action_table 46 | 47 | 48 | let s:findsymbols = { 49 | \ 'name': 'OmniSharp/findsymbols', 50 | \ 'description': 'candidates from C# symbols via OmniSharp', 51 | \ 'default_kind': 'jump_list', 52 | \ } 53 | function! s:findsymbols.gather_candidates(args, context) abort 54 | let quickfixes = get(a:args, 0, []) 55 | return map(quickfixes, '{ 56 | \ "word": get(split(v:val.text, "\t"), 0), 57 | \ "abbr": v:val.text, 58 | \ "action__path": v:val.filename, 59 | \ "action__line": v:val.lnum, 60 | \ "action__col": v:val.col, 61 | \ }') 62 | endfunction 63 | 64 | 65 | function! unite#sources#OmniSharp#define() abort 66 | return [s:findcodeactions, s:findsymbols] 67 | endfunction 68 | 69 | let &cpoptions = s:save_cpo 70 | unlet s:save_cpo 71 | 72 | " vim:et:sw=2:sts=2 73 | -------------------------------------------------------------------------------- /ftdetect/cake.vim: -------------------------------------------------------------------------------- 1 | autocmd BufRead,BufNewFile *.cake set filetype=cs 2 | -------------------------------------------------------------------------------- /ftdetect/csx.vim: -------------------------------------------------------------------------------- 1 | autocmd BufRead,BufNewFile *.csx set filetype=cs 2 | -------------------------------------------------------------------------------- /ftdetect/omnisharplog.vim: -------------------------------------------------------------------------------- 1 | autocmd BufRead,BufNewFile *omnisharp.log set filetype=omnisharplog 2 | -------------------------------------------------------------------------------- /ftplugin/omnisharplog/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | set foldlevel=0 2 | set foldmethod=syntax 3 | -------------------------------------------------------------------------------- /installer/README.md: -------------------------------------------------------------------------------- 1 | # OmniSharp-Roslyn server management scripts 2 | 3 | The OmniSharp installer scripts are used by OmniSharp-vim to automate the installation and updating of the [OmniSharp-Rosyln server](https://github.com/OmniSharp/omnisharp-roslyn). There is a script for [Linux, macOS and Cygwin/WSL](#unix-like-oss), and another for [Microsoft Windows](#microsoft-windows). 4 | 5 | ## Unix-like OSs 6 | 7 | _Works on: Linux, Apple macOS, Cygwin and Windows Subsystem for Linux._ 8 | 9 | ### Usage 10 | 11 | ``` 12 | ./omnisharp-manager.sh [-v VERSION] [-l PATH] [-HMuh] 13 | ``` 14 | 15 | | Option | Description | 16 | |--------------|---------------------------------------------------------------------------------------------| 17 | | `-v VERSION` | Version number of the server to install (defaults to the latest verison). | 18 | | `-l PATH` | Location to install the server to (defaults to `$HOME/.omnisharp/`). | 19 | | `-H` | Install the HTTP variant of the server (if not given, the stdio variant will be installed). | 20 | | `-M` | Use the system Mono installation rather than the one packaged with OmniSharp-Roslyn. | 21 | | `-u` | Display simple usage information. | 22 | | `-h` | Display this help message. | 23 | 24 | ## Microsoft Windows 25 | 26 | _Works on: Microsoft Windows._ 27 | 28 | ### Usage 29 | 30 | ``` 31 | .\omnisharp-manager.ps1 [-v VERSION] [-l PATH] [-Hu] 32 | ``` 33 | 34 | | Option | Description | 35 | |--------------|---------------------------------------------------------------------------------------------| 36 | | `-v VERSION` | Version number of server to install (defaults to the latest version). | 37 | | `-l PATH` | Location to install the server to (defaults to `%USERPROFILE%\.omnisharp\`). | 38 | | `-H` | Install the HTTP variant of the server (if not given, the stdio variant will be installed). | 39 | | `-u` | Display simple usage information. | 40 | 41 | ### Output 42 | 43 | After downloading and installing the server the script will check for the `OmniSharp.Roslyn.dll` library in the install directory. If it locates the file an exit code of `0` will be returned. If it does not it will return a `1`. You can check exit codes in PowerShell by running `$LASTEXITCODE` in the console after running the script. 44 | 45 | ### Examples 46 | 47 | In PowerShell, the following will install version 1.32.1 of the HTTP OmniSharp Roslyn server in the `%USERPROFILE%\.omnisharp\omnisharp-roslyn` directory. 48 | 49 | ```powershell 50 | cd "C:\Users\My Name\vimfiles\pack\plugins\opt\omnisharp-vim" # Navigate to the OmniSharp-vim plugin directory 51 | .\installer\omnisharp-manager.ps1 -v "v1.32.1" -H -l "$Env:USERPROFILE\.omnisharp\omnisharp-roslyn" 52 | ``` 53 | -------------------------------------------------------------------------------- /installer/omnisharp-manager.ps1: -------------------------------------------------------------------------------- 1 | # OmniSharp-roslyn Management tool 2 | # 3 | # Works on: Microsoft Windows 4 | 5 | # Options: 6 | # -v | version to use (otherwise use latest) 7 | # -l | where to install the server 8 | # -6 | install the net6.0 server version 9 | # -u | help / usage info 10 | # -H | install the HTTP version of the server 11 | 12 | [CmdletBinding()] 13 | param( 14 | [Parameter()][Alias('v')][string]$version, 15 | [Parameter()][Alias('l')][string]$location = "$($Env:USERPROFILE)\.omnisharp\", 16 | [Parameter()][Alias('6')][Switch]$use_net6, 17 | [Parameter()][Alias('u')][Switch]$usage, 18 | [Parameter()][Alias('H')][Switch]$http_check 19 | ) 20 | 21 | if ($usage) { 22 | Write-Host "usage:" $MyInvocation.MyCommand.Name "[-Hu] [-v version] [-6] [-l location]" 23 | exit 24 | } 25 | 26 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 27 | 28 | function get_latest_version() { 29 | $response = Invoke-RestMethod -Uri "https://api.github.com/repos/OmniSharp/omnisharp-roslyn/releases/latest" 30 | return $response.tag_name 31 | } 32 | 33 | if ([string]::IsNullOrEmpty($version)) { 34 | $version = get_latest_version 35 | } 36 | 37 | if ($use_net6) { 38 | $net6 = "-net6.0" 39 | } else { 40 | $net6 = "" 41 | } 42 | 43 | if ($http_check) { 44 | $http = ".http" 45 | } else { 46 | $http = "" 47 | } 48 | 49 | if ([Environment]::Is64BitOperatingSystem) { 50 | $machine = "x64" 51 | } else { 52 | $machine = "x86" 53 | } 54 | 55 | $url = "https://github.com/OmniSharp/omnisharp-roslyn/releases/download/$($version)/omnisharp$($http)-win-$($machine)$($net6).zip" 56 | $out = "$($location)\omnisharp$($http)-win-$($machine).zip" 57 | 58 | if (Test-Path -Path $location) { 59 | Remove-Item $location -Force -Recurse 60 | } 61 | 62 | New-Item -ItemType Directory -Force -Path $location | Out-Null 63 | 64 | Invoke-WebRequest -Uri $url -OutFile $out 65 | 66 | # Run Expand-Archive in versions that support it 67 | if ($PSVersionTable.PSVersion.Major -gt 4) { 68 | Expand-Archive $out $location -Force 69 | } else { 70 | Add-Type -AssemblyName System.IO.Compression.FileSystem 71 | [System.IO.Compression.ZipFile]::ExtractToDirectory($out, $location) 72 | } 73 | 74 | # Check for file to confirm download and unzip were successful 75 | if (Test-Path -Path "$($location)\OmniSharp.Roslyn.dll") { 76 | Set-Content -Path "$($location)\OmniSharpInstall-version.txt" -Value "$($version)" 77 | exit 0 78 | } else { 79 | exit 1 80 | } 81 | -------------------------------------------------------------------------------- /installer/omnisharp-manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # OmniSharp-Roslyn Installer 3 | # 4 | # Works on: Linux, macOS & Cygwin/WSL & MinGW 5 | 6 | usage() { 7 | printf "usage: %s [-HMuh] [-v version] [-l location]\\n" "$0" 8 | } 9 | 10 | print_help() { 11 | cat << EOF 12 | $(usage) 13 | 14 | Options: 15 | -v | Version to install (if omitted, fetch latest) 16 | -l | Directory to install the server to (upon install, this directory will be cleared) 17 | -6 | Use the net6.0 server version 18 | -u | Usage info 19 | -h | Help message 20 | -H | Install the HTTP version of the server 21 | -M | Use the system Mono rather than the bundled Mono 22 | -W | Use the Windows version of the server (used from WSL) 23 | EOF 24 | } 25 | 26 | get_latest_version() { 27 | if command -v curl >/dev/null 2>&1 ; then 28 | curl --user-agent "curl" --silent "https://api.github.com/repos/OmniSharp/omnisharp-roslyn/releases/latest" 29 | elif command -v wget >/dev/null 2>&1 ; then 30 | wget -qO- "https://api.github.com/repos/OmniSharp/omnisharp-roslyn/releases/latest" 31 | fi | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' 32 | } 33 | 34 | location="$HOME/.omnisharp/" 35 | 36 | while getopts v:l:6HMWuh o "$@" 37 | do 38 | case "$o" in 39 | v) version="$OPTARG";; 40 | l) location="$OPTARG";; 41 | 6) net6=1;; 42 | H) http=".http";; 43 | M) mono=1;; 44 | W) windows=1;; 45 | u) usage && exit 0;; 46 | h) print_help && exit 0;; 47 | [?]) usage && exit 1;; 48 | esac 49 | done 50 | 51 | # Ensure that either 'curl' or 'wget' is installed 52 | if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1 ; then 53 | echo "Error: the installer requires either 'curl' or 'wget'" 54 | exit 1 55 | fi 56 | 57 | # Check that either 'tar' or 'unzip' is installed 58 | # (and set the file extension appropriately) 59 | if command -v tar >/dev/null 2>&1 && command -v gzip >/dev/null 2>&1 ; then 60 | ext="tar.gz" 61 | elif command -v unzip >/dev/null 2>&1 ; then 62 | ext="zip" 63 | else 64 | echo "Error: the installer requires either 'tar' or 'unzip'" 65 | exit 1 66 | fi 67 | 68 | # If not installing in mono mode 69 | if [ -z "$mono" ]; then 70 | # Check the machine architecture 71 | case "$(uname -m)" in 72 | "x86_64") machine="x64";; 73 | "i368") machine="x86";; 74 | "arm64") machine="arm64";; 75 | "aarch64") machine="arm64";; 76 | *) 77 | echo "Error: architecture not supported" 78 | exit 1 79 | ;; 80 | esac 81 | fi 82 | 83 | if [ -n "$mono" ]; then 84 | os="mono" 85 | else 86 | case "$(uname -s)" in 87 | "Linux") 88 | if [ -n "$net6" ]; then 89 | os="linux-${machine}-net6.0" 90 | else 91 | os="linux-${machine}" 92 | fi 93 | ;; 94 | "Darwin") 95 | if [ -n "$net6" ]; then 96 | os="osx-${machine}-net6.0" 97 | else 98 | os="osx" 99 | fi 100 | ;; 101 | *) 102 | if [ "$(uname -o)" = "Cygwin" ]; then 103 | os="win-${machine}" 104 | 105 | if command -v unzip >/dev/null 2>&1 ; then 106 | ext="zip" 107 | else 108 | echo "Error: the installer requires 'unzip' to work on Cygwin" 109 | exit 1 110 | fi 111 | elif [ "$(uname -o)" = "Msys" ]; then 112 | os="win-${machine}" 113 | 114 | if command -v unzip >/dev/null 2>&1 ; then 115 | ext="zip" 116 | else 117 | echo "Error: the installer requires 'unzip' to work on MinGW" 118 | exit 1 119 | fi 120 | else 121 | printf "Error: unknown system: %s\\n" "$(uname -s)" 122 | exit 1 123 | fi 124 | ;; 125 | esac 126 | fi 127 | 128 | if [ -n "$windows" ]; then 129 | os="win-${machine}" 130 | 131 | if command -v unzip >/dev/null 2>&1 ; then 132 | ext="zip" 133 | else 134 | echo "Error: the installer requires 'unzip' to work on WSL" 135 | exit 1 136 | fi 137 | fi 138 | 139 | file_name="omnisharp${http}-${os}.${ext}" 140 | 141 | [ -z "$version" ] && version="$(get_latest_version)" 142 | 143 | base_url="https://github.com/OmniSharp/omnisharp-roslyn/releases/download" 144 | full_url="${base_url}/${version}/${file_name}" 145 | # echo "$full_url" 146 | 147 | download_location="${location}-${version}" 148 | 149 | rm -rf "$download_location" 150 | mkdir -p "$download_location" 151 | 152 | if command -v curl >/dev/null 2>&1 ; then 153 | curl -L "$full_url" -o "$download_location/$file_name" 154 | elif command -v wget >/dev/null 2>&1 ; then 155 | wget -P "$download_location" "$full_url" 156 | fi 157 | 158 | # Check if the server was successfully downloaded 159 | if [ $? -gt 0 ] || [ ! -f "$download_location/$file_name" ]; then 160 | echo "Error: failed to download the server, possibly a network issue" 161 | exit 1 162 | fi 163 | 164 | set -eu 165 | if [ "$ext" = "zip" ]; then 166 | unzip "$download_location/$file_name" -d "$download_location/" 167 | find "$download_location" -type f -exec chmod +x {} + 168 | else 169 | tar -zxvf "$download_location/$file_name" -C "$download_location/" 170 | fi 171 | 172 | rm -rf "$location" 173 | mv "$download_location" "$location" 174 | set +eu 175 | 176 | # If using the system Mono, make the files executable 177 | if [ -n "$mono" ] && [ $mono -eq 1 ]; then 178 | find "$location" -type f -exec chmod +x {} + 179 | elif [ -z "$net6" ]; then 180 | find "$location/run" -type f -exec chmod +x {} + 181 | fi 182 | 183 | echo "$version" > "$location/OmniSharpInstall-version.txt" 184 | echo "$full_url" >> "$location/OmniSharpInstall-version.txt" 185 | 186 | exit 0 187 | -------------------------------------------------------------------------------- /log/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OmniSharp/omnisharp-vim/cdbf65bc4385d7026428d2f392b40a317725cc9c/log/.placeholder -------------------------------------------------------------------------------- /plugin/OmniSharp.vim: -------------------------------------------------------------------------------- 1 | if exists('g:OmniSharp_loaded') | finish | endif 2 | let g:OmniSharp_loaded = 1 3 | 4 | let g:OmniSharp_lookup_metadata = get(g:, 'OmniSharp_lookup_metadata', 1) 5 | 6 | " Default to `1`, except in cygwin defaults to `0` 7 | let g:OmniSharp_server_stdio = get(g:, 'OmniSharp_server_stdio', !has('win32unix')) 8 | 9 | let g:OmniSharp_server_display_loading = get(g:, 'OmniSharp_server_display_loading', 1) 10 | let g:OmniSharp_server_loading_timeout = get(g:, 'OmniSharp_server_loading_timeout', 180) 11 | 12 | " Use mono to start the roslyn server on *nix 13 | let g:OmniSharp_server_use_mono = get(g:, 'OmniSharp_server_use_mono', 0) 14 | 15 | " Use the native net6.0 server build 16 | let g:OmniSharp_server_use_net6 = get(g:, 'OmniSharp_server_use_net6', 0) 17 | 18 | let g:OmniSharp_open_quickfix = get(g:, 'OmniSharp_open_quickfix', 1) 19 | 20 | let g:OmniSharp_timeout = get(g:, 'OmniSharp_timeout', 1) 21 | 22 | " Default to `0`, except in cygwin 23 | let g:OmniSharp_translate_cygwin_wsl = get(g:, 'OmniSharp_translate_cygwin_wsl', has('win32unix')) 24 | 25 | let g:OmniSharp_typeLookupInPreview = get(g:, 'OmniSharp_typeLookupInPreview', 0) 26 | 27 | let g:OmniSharp_sln_list_index = get(g:, 'OmniSharp_sln_list_index', -1) 28 | 29 | let g:OmniSharp_autoselect_existing_sln = get(g:, 'OmniSharp_autoselect_existing_sln', 0) 30 | let g:OmniSharp_prefer_global_sln = get(g:, 'OmniSharp_prefer_global_sln', 0) 31 | let g:OmniSharp_start_without_solution = get(g:, 'OmniSharp_start_without_solution', 1) 32 | 33 | " Automatically start server 34 | let g:OmniSharp_start_server = get(g:, 'OmniSharp_start_server', get(g:, 'Omnisharp_start_server', 1)) 35 | 36 | let defaultlevel = g:OmniSharp_server_stdio ? 'info' : 'warning' 37 | let g:OmniSharp_loglevel = get(g:, 'OmniSharp_loglevel', defaultlevel) 38 | 39 | let g:OmniSharp_diagnostic_listen = get(g:, 'OmniSharp_diagnostic_listen', 2) 40 | 41 | let g:OmniSharp_runtests_parallel = get(g:, 'OmniSharp_runtests_parallel', 1) 42 | let g:OmniSharp_runtests_echo_output = get(g:, 'OmniSharp_runtests_echo_output', 1) 43 | 44 | " Set to 1 when ultisnips is installed 45 | let g:OmniSharp_want_snippet = get(g:, 'OmniSharp_want_snippet', 0) 46 | 47 | " Only has effect if OmniSharp_want_snippet is 0. 48 | let g:OmniSharp_completion_without_overloads = get(g:, 'OmniSharp_completion_without_overloads', 0) 49 | 50 | " Does not work well when OmniSharp_want_snippet is 1. 51 | let g:OmniSharp_coc_snippet = get(g:, 'OmniSharp_coc_snippet', 0) 52 | 53 | let g:omnicomplete_fetch_full_documentation = get(g:, 'omnicomplete_fetch_full_documentation', 1) 54 | 55 | command! -bar -nargs=? OmniSharpInstall call OmniSharp#Install() 56 | command! -bar -nargs=? OmniSharpOpenLog call OmniSharp#log#Open() 57 | command! -bar -bang OmniSharpStatus call OmniSharp#Status(0) 58 | 59 | " Preserve backwards compatibility with older version g:OmniSharp_highlight_types 60 | let g:OmniSharp_highlighting = get(g:, 'OmniSharp_highlighting', get(g:, 'OmniSharp_highlight_types', 2)) 61 | 62 | augroup OmniSharp_Integrations 63 | autocmd! 64 | 65 | " Initialize OmniSharp as an asyncomplete source 66 | autocmd User asyncomplete_setup call asyncomplete#register_source({ 67 | \ 'name': 'OmniSharp', 68 | \ 'whitelist': ['cs'], 69 | \ 'completor': function('asyncomplete#sources#OmniSharp#completor') 70 | \}) 71 | 72 | autocmd User Ncm2Plugin call ncm2#register_source({ 73 | \ 'name': 'OmniSharp-vim', 74 | \ 'priority': 9, 75 | \ 'scope': ['cs'], 76 | \ 'mark': 'OS', 77 | \ 'subscope_enable': 1, 78 | \ 'complete_length': 3, 79 | \ 'complete_pattern': ['\.'], 80 | \ 'on_complete': function('ncm2#sources#OmniSharp#on_complete') 81 | \}) 82 | 83 | " Listen for ALE requests 84 | autocmd User ALEWantResults call ale#sources#OmniSharp#WantResults() 85 | augroup END 86 | 87 | if !exists('g:OmniSharp_selector_ui') 88 | let g:OmniSharp_selector_ui = get(filter( 89 | \ ['unite', 'ctrlp', 'fzf','clap'], 90 | \ '!empty(globpath(&runtimepath, printf("plugin/%s.vim", v:val), 1))' 91 | \ ), 0, '') 92 | endif 93 | if g:OmniSharp_selector_ui ==? 'ctrlp' 94 | let g:ctrlp_extensions = get(g:, 'ctrlp_extensions', []) 95 | if !exists('g:OmniSharp_ctrlp_extensions_added') 96 | let g:OmniSharp_ctrlp_extensions_added = 1 97 | let g:ctrlp_extensions += ['findsymbols', 'findcodeactions'] 98 | endif 99 | endif 100 | 101 | " vim:et:sw=2:sts=2 102 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | *.egg-info/ 3 | .cache/ 4 | .tox/ 5 | __cache__/ 6 | .pytest_cache/ 7 | 8 | *.pyc 9 | -------------------------------------------------------------------------------- /python/.python-version: -------------------------------------------------------------------------------- 1 | 3.6.10 2 | 3.7.10 3 | 3.8.8 4 | 3.9.2 5 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Python module for the plug-in 2 | 3 | The tests should be kept in the `tests` folder. 4 | 5 | ## Setup 6 | 7 | Pip should is bundled with recent releases of Python (`2.7.9+` and `3.4`) [[StackOverflow](https://stackoverflow.com/a/12476379)], hence the easiest way to set `tox` up is via `pip` unless a system package manager is your preferred choice. 8 | Instructions: 9 | 10 | - Install the latest Python `2.7.x` release from [python.org](https://www.python.org/downloads/). 11 | - Install `tox`: 12 | - Via `pip` from command prompt or terminal application: 13 | ``` 14 | $ pip install tox 15 | ``` 16 | - Via your own package manager. 17 | 18 | ## Activating the tox virtual environments 19 | 20 | In order to activate a specific python environment configured with `tox` execute the following: 21 | 22 | ```bash 23 | source .tox/${PYTHON_VERSION_LABEL}/bin/activate 24 | ``` 25 | 26 | ## Setup instructions for pyenv for UNIX 27 | 28 | The script `pyenv-bootstrap.sh` can be used for setting up different versions 29 | of the interpreters on Linux and Mac machines. 30 | 31 | Unfortunately `pyenv` is not supported on Windows, so you will need to install 32 | the interpreters manually. 33 | -------------------------------------------------------------------------------- /python/ale_lint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from __future__ import print_function 4 | 5 | import argparse 6 | import logging 7 | import os 8 | import sys 9 | from os.path import join, pardir, realpath 10 | 11 | from omnisharp.util import UtilCtx, getResponse, quickfixes_from_response 12 | 13 | 14 | def _setup_logging(level): 15 | logger = logging.getLogger('omnisharp') 16 | logger.setLevel(level) 17 | 18 | log_dir = realpath(join(__file__, pardir, pardir, 'log')) 19 | if not os.path.exists(log_dir): 20 | os.makedirs(log_dir) 21 | log_file = os.path.join(log_dir, 'lint.log') 22 | hdlr = logging.FileHandler(log_file) 23 | logger.addHandler(hdlr) 24 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 25 | hdlr.setFormatter(formatter) 26 | return logger 27 | 28 | 29 | def main(): 30 | """ Run a /codecheck on a file """ 31 | 32 | log_levels = { 33 | 'debug': logging.DEBUG, 34 | 'info': logging.INFO, 35 | 'warning': logging.WARNING, 36 | 'error': logging.ERROR, 37 | 'critical': logging.CRITICAL, 38 | } 39 | 40 | parser = argparse.ArgumentParser(description=main.__doc__) 41 | parser.add_argument('--host', required=True, 42 | help="Host and port of omnisharp server") 43 | parser.add_argument('--filename', required=True, 44 | help="Path of the file being checked") 45 | parser.add_argument('--cwd', help="Current working directory of vim", 46 | default='') 47 | parser.add_argument('--delimiter', default=':', 48 | help="Delimiter for output (default %(default)s)") 49 | parser.add_argument('--level', help="Log level (default %(default)s)", 50 | choices=log_levels.keys(), default='info') 51 | parser.add_argument('--translate', action='store_true', 52 | help="If provided, translate cygwin/wsl paths") 53 | parser.add_argument('--encoding', required=True, 54 | help="Encoding for output") 55 | args = parser.parse_args() 56 | logger = _setup_logging(log_levels[args.level]) 57 | try: 58 | do_codecheck(logger, args.filename.strip(), args.host, args.cwd, 59 | args.translate, args.delimiter, args.encoding) 60 | except Exception as e: 61 | logger.exception("Error doing codecheck") 62 | 63 | 64 | def do_codecheck(logger, filename, host, cwd, translate, delimiter, encoding): 65 | ctx = UtilCtx( 66 | buffer_name=filename, 67 | translate_cygwin_wsl=translate, 68 | cwd=cwd, 69 | timeout=4, 70 | host=host, 71 | buffer=''.join(sys.stdin), 72 | ) 73 | 74 | response = getResponse(ctx, '/codecheck', json=True) 75 | quickfixes = quickfixes_from_response(ctx, response['QuickFixes']) 76 | 77 | keys = ['filename', 'lnum', 'col', 'type', 'subtype', 'text'] 78 | for item in quickfixes: 79 | s = delimiter.join([str(item.get(k, '')) for k in keys]) + '\n' 80 | if sys.version_info.major == 3: 81 | sys.stdout.buffer.write(s.encode(encoding)) 82 | elif sys.version_info.major == 2: 83 | sys.stdout.write(unicode(s).encode(encoding)) 84 | 85 | 86 | if __name__ == '__main__': 87 | main() 88 | -------------------------------------------------------------------------------- /python/bootstrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Bootstrap the python environment for use with vim 5 | 6 | Sets up logging and imports commands into namespace 7 | 8 | """ 9 | 10 | import logging 11 | import os 12 | import os.path 13 | 14 | import vim # pylint: disable=import-error 15 | from omnisharp.commands import * 16 | from omnisharp.vimcmd import vimcmd 17 | 18 | _log_file = '' 19 | 20 | 21 | def _setup_logging(): 22 | global _log_file 23 | logger = logging.getLogger('omnisharp') 24 | level = vim.eval('g:OmniSharp_loglevel').upper() 25 | logger.setLevel(getattr(logging, level)) 26 | 27 | log_dir = os.path.realpath(os.path.join( 28 | vim.eval('g:OmniSharp_python_path'), 29 | '..', 30 | 'log')) 31 | if not os.path.exists(log_dir): 32 | os.makedirs(log_dir) 33 | _log_file = os.path.join(log_dir, 'python.log') 34 | hdlr = logging.FileHandler(_log_file) 35 | logger.addHandler(hdlr) 36 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 37 | hdlr.setFormatter(formatter) 38 | 39 | 40 | _setup_logging() 41 | 42 | 43 | @vimcmd 44 | def getLogFile(): 45 | return _log_file 46 | -------------------------------------------------------------------------------- /python/omnisharp/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | -------------------------------------------------------------------------------- /python/omnisharp/exceptions.py: -------------------------------------------------------------------------------- 1 | """ Exceptions thrown by the omnisharp-vim plugin """ 2 | 3 | 4 | class ServerConnectionError(Exception): 5 | """ There was an error when trying to communicate to the server """ 6 | code = "CONNECTION" 7 | 8 | 9 | class BadResponseError(Exception): 10 | """ Received a malformed response from the server """ 11 | code = "BAD_RESPONSE" 12 | -------------------------------------------------------------------------------- /python/omnisharp/util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ Utilities """ 3 | 4 | import json as jsonlib 5 | import logging 6 | import os.path 7 | import platform 8 | import re 9 | import socket 10 | import sys 11 | from contextlib import closing 12 | 13 | from .exceptions import BadResponseError, ServerConnectionError 14 | 15 | try: 16 | from urllib import parse as urlparse 17 | from urllib import request 18 | except ImportError: 19 | import urllib2 as request 20 | import urlparse 21 | 22 | 23 | logger = logging.getLogger('omnisharp.util') 24 | 25 | 26 | class BaseCtx(object): 27 | """ 28 | Provides properties that will be shared by all implementations of UtilCtx 29 | """ 30 | 31 | def __init__(self): 32 | self.is_msys = 'msys_nt' in platform.system().lower() 33 | self.is_cygwin = 'cygwin' in platform.system().lower() 34 | self.is_wsl = ('linux' in platform.system().lower() 35 | and 'microsoft' in platform.release().lower()) 36 | 37 | 38 | class UtilCtx(BaseCtx): 39 | """ 40 | Simple class that holds data that is needed by util functions 41 | 42 | Most of the util methods require this object (or an equivalent replacement) 43 | when they are called. The indirection here is to make two things easier: 44 | testing, and running outside of a vim context. 45 | 46 | Tests become easier because instead of mocking vim API functions, you can 47 | just pass in an object with whatever test data you wish. As a bonus, as 48 | long as the interface to the UtilCtx doesn't change, you can refactor the 49 | vim implementation all you like without breaking tests. 50 | 51 | Running outside a vim context is easier too, for the same reason as tests. 52 | This is useful for such purposes as an ALE linter script. 53 | 54 | """ 55 | 56 | def __init__( 57 | self, 58 | buffer_name='', 59 | translate_cygwin_wsl=False, 60 | cwd='', 61 | timeout=1, 62 | host='', 63 | line=1, 64 | column=1, 65 | buffer='', 66 | ): 67 | super(UtilCtx, self).__init__() 68 | self.buffer_name = buffer_name 69 | self.translate_cygwin_wsl = translate_cygwin_wsl 70 | self.cwd = cwd 71 | self.timeout = timeout 72 | self.host = host 73 | self.line = line 74 | self.column = column 75 | self.buffer = buffer 76 | 77 | 78 | class VimUtilCtx(BaseCtx): 79 | """ Implementation of a UtilCtx that gets data from vim API """ 80 | def __init__(self, vim): 81 | super(VimUtilCtx, self).__init__() 82 | self._vim = vim 83 | 84 | @property 85 | def buffer_name(self): 86 | # We can't use self._vim.current.buffer.name because it returns the real 87 | # path. expand('%') will preserve the symlinked path, if one exists. 88 | return self._vim.eval("expand('%:p')") 89 | 90 | @property 91 | def translate_cygwin_wsl(self): 92 | return bool(int(self._vim.eval('g:OmniSharp_translate_cygwin_wsl'))) 93 | 94 | @property 95 | def cwd(self): 96 | return self._vim.eval('getcwd()') 97 | 98 | @property 99 | def timeout(self): 100 | return int(self._vim.eval('g:OmniSharp_timeout')) 101 | 102 | @property 103 | def host(self): 104 | return self._vim.eval('OmniSharp#GetHost()') 105 | 106 | @property 107 | def line(self): 108 | return self._vim.current.window.cursor[0] 109 | 110 | @property 111 | def column(self): 112 | return self._vim.current.window.cursor[1] + 1 113 | 114 | @property 115 | def buffer(self): 116 | return '\r\n'.join(self._vim.eval("getline(1,'$')")[:]) 117 | 118 | 119 | def quickfixes_from_response(ctx, response): 120 | items = [] 121 | for quickfix in response: 122 | # syntax errors returns 'Message' instead of 'Text'. 123 | # I need to sort this out. 124 | text = quickfix.get('Text') or quickfix.get('Message', '') 125 | 126 | filename = quickfix.get('FileName') 127 | if filename is None: 128 | filename = ctx.buffer_name 129 | else: 130 | filename = formatPathForClient(ctx, filename) 131 | 132 | item = { 133 | 'filename': filename, 134 | 'text': text, 135 | 'lnum': quickfix['Line'], 136 | 'col': quickfix['Column'], 137 | 'vcol': 0 138 | } 139 | if 'LogLevel' in quickfix: 140 | item['type'] = 'E' if quickfix['LogLevel'] == 'Error' else 'W' 141 | if quickfix['LogLevel'] == 'Hidden': 142 | item['subtype'] = 'Style' 143 | 144 | items.append(item) 145 | 146 | return items 147 | 148 | 149 | # When working in Windows Subsystem for Linux (WSL) or Cygwin, vim uses 150 | # unix-style paths but OmniSharp (with a Windows binary) uses Windows 151 | # paths. This means that filenames returned FROM OmniSharp must be 152 | # translated from e.g. "C:\path\to\file" to "/mnt/c/path/to/file", and 153 | # filenames sent TO OmniSharp must be translated in the other direction. 154 | def formatPathForServer(ctx, filepath): 155 | if ctx.translate_cygwin_wsl and (ctx.is_msys or ctx.is_cygwin or ctx.is_wsl): 156 | if ctx.is_msys: 157 | pattern = r'^/([a-zA-Z])/' 158 | elif ctx.is_cygwin: 159 | pattern = r'^/cygdrive/([a-zA-Z])/' 160 | else: 161 | pattern = r'^/mnt/([a-zA-Z])/' 162 | 163 | def drive_replace(match): 164 | return match.group(1).upper() + ':\\' 165 | 166 | return re.sub(pattern, drive_replace, filepath).replace('/', '\\') 167 | return filepath 168 | 169 | 170 | def formatPathForClient(ctx, filepath): 171 | if ctx.translate_cygwin_wsl and (ctx.is_msys or ctx.is_cygwin or ctx.is_wsl): 172 | def path_replace(matchobj): 173 | if ctx.is_msys: 174 | prefix = '/{0}/' 175 | elif ctx.is_cygwin: 176 | prefix = '/cygdrive/{0}/' 177 | else: 178 | prefix = '/mnt/{0}/' 179 | return prefix.format(matchobj.group(1).lower()) 180 | return re.sub(r'^([a-zA-Z]):\\', path_replace, filepath).replace('\\', '/') 181 | # Shorten path names by checking if we can make them relative 182 | cwd = ctx.cwd 183 | if cwd and os.path.commonprefix([cwd, filepath]) == cwd: 184 | filepath = filepath[len(cwd):].lstrip('/\\') 185 | return filepath 186 | 187 | 188 | def getResponse(ctx, path, additional_parameters=None, timeout=None, json=False): 189 | parameters = {} 190 | parameters['line'] = ctx.line 191 | parameters['column'] = ctx.column 192 | parameters['buffer'] = ctx.buffer 193 | parameters['filename'] = formatPathForServer(ctx, ctx.buffer_name) 194 | if additional_parameters is not None: 195 | parameters.update(additional_parameters) 196 | 197 | if timeout is None: 198 | timeout = ctx.timeout 199 | 200 | return doRequest(ctx.host, path, parameters, timeout=timeout, 201 | json=json) 202 | 203 | 204 | def doRequest(host, path, parameters, timeout=1, json=False): 205 | target = urlparse.urljoin(host, path) 206 | 207 | proxy = request.ProxyHandler({}) 208 | opener = request.build_opener(proxy) 209 | req = request.Request(target) 210 | req.add_header('Content-Type', 'application/json') 211 | body = jsonlib.dumps(parameters) 212 | 213 | if sys.version_info >= (3, 0): 214 | body = body.encode('utf-8') 215 | 216 | logger.info("Request: %s", target) 217 | logger.debug(body) 218 | 219 | try: 220 | response = opener.open(req, body, timeout) 221 | res = response.read() 222 | except Exception as e: 223 | logger.exception("Could not connect to OmniSharp server: %s", target) 224 | raise ServerConnectionError(str(e)) 225 | 226 | if sys.version_info >= (3, 0): 227 | res = res.decode('utf-8') 228 | if res.startswith("\xef\xbb\xbf"): # Drop UTF-8 BOM 229 | res = res[3:] 230 | 231 | logger.info("Received Response: %s", target) 232 | logger.debug(res) 233 | if json: 234 | try: 235 | return jsonlib.loads(res) 236 | except Exception as e: 237 | logger.error("Error parsing response as json: \n%s", res) 238 | raise BadResponseError(str(e)) 239 | return res 240 | 241 | 242 | def find_free_port(): 243 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 244 | with closing(sock): 245 | sock.bind(('', 0)) 246 | return sock.getsockname()[1] 247 | -------------------------------------------------------------------------------- /python/omnisharp/vimcmd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Provides vimcmd, a wrapper for python functions that will be called from vim 4 | """ 5 | 6 | import functools 7 | import json 8 | import logging 9 | 10 | try: 11 | import vim # pylint: disable=import-error 12 | _has_vim = True 13 | except ImportError: 14 | _has_vim = False 15 | 16 | logger = logging.getLogger('omnisharp') 17 | 18 | 19 | def vimcmd(fxn): 20 | """ Decorator for functions that will be run from vim """ 21 | 22 | @functools.wraps(fxn) 23 | def wrapper(*args, **kwargs): 24 | try: 25 | ret = fxn(*args, **kwargs) 26 | except Exception as e: 27 | logger.exception("Error running python %s()", fxn.__name__) 28 | _set_return_error(e) 29 | return 0 30 | else: 31 | _set_return_error(None) 32 | return ret 33 | wrapper.is_cmd = True 34 | return wrapper 35 | 36 | 37 | def _set_return_error(err): 38 | # If we're not in a vim plugin, don't try to set the error 39 | if not _has_vim: 40 | return 41 | 42 | # Exceptions don't really work across the vim-python boundary, so instead 43 | # we catch the exception and set it into a global variable. The calling vim 44 | # code will then manually check that value after the command completes. 45 | if err is None: 46 | vim.command('let g:OmniSharp_py_err = {}') 47 | else: 48 | err_dict = { 49 | "code": getattr(err, 'code', 'ERROR'), 50 | "msg": str(err), 51 | } 52 | # Not the best way to serialize to vim types, 53 | # but it'll work for this specific case 54 | vim.command("let g:OmniSharp_py_err = %s" % json.dumps(err_dict)) 55 | -------------------------------------------------------------------------------- /python/pyenv-bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install pyenv by using this: https://github.com/yyuu/pyenv-installer 4 | echo "Installing pyenv for easy setup of interpreters" 5 | curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash 6 | 7 | echo "Do not forget to set the PATH for pyenv to work correctly afterwards!" 8 | 9 | export PATH="${HOME}/.pyenv/bin:$PATH" 10 | eval "$(pyenv init -)" 11 | eval "$(pyenv virtualenv-init -)" 12 | 13 | echo "Setting up python interpreters for testing with tox" 14 | echo "WARNING: this will take a long while the first time!" 15 | for v in `cat .python-version` 16 | do 17 | pyenv install $v 18 | done 19 | -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore=E501,W504,W503 3 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | See: 3 | https://packaging.python.org/en/latest/distributing.html 4 | https://github.com/pypa/sampleproject 5 | """ 6 | 7 | # Always prefer setuptools over distutils 8 | from setuptools import find_packages, setup 9 | 10 | setup( 11 | name='omnisharp', 12 | 13 | # Versions should comply with PEP440. For a discussion on single-sourcing 14 | # the version across setup.py and the project code, see 15 | # https://packaging.python.org/en/latest/single_source_version.html 16 | version='1.0.0', 17 | 18 | description='OmniSharp python module', 19 | long_description='', 20 | 21 | # The project's main homepage. 22 | url='https://github.com/OmniSharp/omnisharp-vim', 23 | 24 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 25 | classifiers=[ 26 | # Indicate who your project is intended for 27 | 'Intended Audience :: Developers', 28 | 'Topic :: Software Development :: Build Tools', 29 | 30 | # Specify the Python versions you support here. In particular, ensure 31 | # that you indicate whether you support Python 2, Python 3 or both. 32 | 'Programming Language :: Python :: 2', 33 | 'Programming Language :: Python :: 2.7', 34 | 'Programming Language :: Python :: 3', 35 | 'Programming Language :: Python :: 3.6', 36 | 'Programming Language :: Python :: 3.7', 37 | 'Programming Language :: Python :: 3.8', 38 | 'Programming Language :: Python :: 3.9', 39 | ], 40 | 41 | # What does your project relate to? 42 | keywords='development csharp', 43 | 44 | # You can just specify the packages manually here if your project is 45 | # simple. Or you can use find_packages(). 46 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 47 | 48 | # Alternatively, if you want to distribute just a my_module.py, uncomment 49 | # this: 50 | # py_modules=["my_module"], 51 | 52 | # List run-time dependencies here. These will be installed by pip when 53 | # your project is installed. For an analysis of "install_requires" vs pip's 54 | # requirements files see: 55 | # https://packaging.python.org/en/latest/requirements.html 56 | install_requires=[], 57 | 58 | # List additional groups of dependencies here (e.g. development 59 | # dependencies). You can install these using the following syntax, 60 | # for example: 61 | # $ pip install -e .[dev,test] 62 | extras_require={ 63 | 'dev': ['check-manifest'], 64 | 'test': ['pytest-cov', 'pytest', 'pylint', 'pycodestyle', 'tox', 65 | 'tox-pyenv', 'pytest-mock'], 66 | }, 67 | ) 68 | -------------------------------------------------------------------------------- /python/tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | -------------------------------------------------------------------------------- /python/tests/test_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | '''Tests for the util.py module''' 5 | 6 | import sys 7 | 8 | import pytest 9 | from omnisharp.exceptions import BadResponseError, ServerConnectionError 10 | from omnisharp.util import (UtilCtx, find_free_port, formatPathForClient, 11 | formatPathForServer, getResponse, 12 | quickfixes_from_response) 13 | 14 | 15 | @pytest.fixture(scope='module') 16 | def ctx(): 17 | return UtilCtx() 18 | 19 | 20 | def test_get_response_no_server(ctx): 21 | '''Test that the getResponse throws when there is no server''' 22 | port = find_free_port() 23 | with pytest.raises(ServerConnectionError): 24 | getResponse(ctx, "http://localhost:%d" % port) 25 | 26 | 27 | def test_get_response_mocked_server(ctx, mocker): 28 | '''Test that we can get a response the server''' 29 | build_opener = mocker.patch('omnisharp.util.request.build_opener') 30 | expected_response = 'Mocked response with UTF-8 BOM' 31 | if sys.version_info >= (3, 0): 32 | mocked_response = ( 33 | '\xef\xbb\xbf' + expected_response).encode('utf-8') 34 | else: 35 | mocked_response = '\xef\xbb\xbf' + expected_response 36 | 37 | build_opener \ 38 | .return_value.open \ 39 | .return_value.read \ 40 | .return_value = mocked_response 41 | 42 | response = getResponse(ctx, "http://my_endpoint") 43 | 44 | assert expected_response == response 45 | 46 | 47 | def test_get_json_response_mocked_server(ctx, mocker): 48 | '''Test that we can get a response the server''' 49 | build_opener = mocker.patch('omnisharp.util.request.build_opener') 50 | expected_response = '{"foo": "bar"}' 51 | if sys.version_info >= (3, 0): 52 | mocked_response = ( 53 | '\xef\xbb\xbf' + expected_response).encode('utf-8') 54 | else: 55 | mocked_response = '\xef\xbb\xbf' + expected_response 56 | 57 | build_opener \ 58 | .return_value.open \ 59 | .return_value.read \ 60 | .return_value = mocked_response 61 | 62 | response = getResponse(ctx, "http://my_endpoint", json=True) 63 | 64 | assert {'foo': 'bar'} == response 65 | 66 | 67 | def test_get_bad_json_response(ctx, mocker): 68 | '''Malformed json response throws BadResponseError''' 69 | build_opener = mocker.patch('omnisharp.util.request.build_opener') 70 | expected_response = '{"foo": "bar"' 71 | if sys.version_info >= (3, 0): 72 | mocked_response = ( 73 | '\xef\xbb\xbf' + expected_response).encode('utf-8') 74 | else: 75 | mocked_response = '\xef\xbb\xbf' + expected_response 76 | 77 | build_opener \ 78 | .return_value.open \ 79 | .return_value.read \ 80 | .return_value = mocked_response 81 | 82 | with pytest.raises(BadResponseError): 83 | getResponse(ctx, "http://my_endpoint", json=True) 84 | 85 | 86 | def test_format_no_translate(ctx): 87 | ctx.translate_cygwin_wsl = False 88 | 89 | path = '/foo/bar/baz' 90 | assert formatPathForClient(ctx, path) == path 91 | 92 | path = '/foo/bar/baz' 93 | assert formatPathForServer(ctx, path) == path 94 | 95 | 96 | def test_format_client_relative(ctx): 97 | ctx.translate_cygwin_wsl = False 98 | ctx.cwd = '/foo' 99 | 100 | path = '/foo/bar/baz' 101 | assert formatPathForClient(ctx, path) == 'bar/baz' 102 | 103 | 104 | def test_translate_for_server(ctx): 105 | ctx.translate_cygwin_wsl = True 106 | ctx.is_msys = True 107 | 108 | path = '/c/foo/bar' 109 | assert formatPathForServer(ctx, path) == r'C:\foo\bar' 110 | 111 | ctx.is_msys = False 112 | ctx.is_cygwin = True 113 | path = '/cygdrive/c/foo/bar' 114 | assert formatPathForServer(ctx, path) == r'C:\foo\bar' 115 | 116 | ctx.is_cygwin = False 117 | ctx.is_wsl = True 118 | path = '/mnt/c/foo/bar' 119 | assert formatPathForServer(ctx, path) == r'C:\foo\bar' 120 | 121 | 122 | def test_translate_for_client(ctx): 123 | ctx.translate_cygwin_wsl = True 124 | ctx.is_msys = True 125 | 126 | path = r'C:\foo\bar' 127 | assert formatPathForClient(ctx, path) == '/c/foo/bar' 128 | 129 | ctx.is_msys = False 130 | ctx.is_cygwin = True 131 | assert formatPathForClient(ctx, path) == '/cygdrive/c/foo/bar' 132 | 133 | ctx.is_cygwin = False 134 | ctx.is_wsl = True 135 | assert formatPathForClient(ctx, path) == '/mnt/c/foo/bar' 136 | 137 | 138 | def test_quickfixes_from_response(ctx): 139 | ctx.translate_cygwin_wsl = False 140 | 141 | response = [ 142 | { 143 | 'FileName': 'foo.cs', 144 | 'Text': 'some text', 145 | 'Line': 5, 146 | 'Column': 8, 147 | }, 148 | ] 149 | qf = quickfixes_from_response(ctx, response) 150 | expected = [ 151 | { 152 | 'filename': 'foo.cs', 153 | 'text': 'some text', 154 | 'lnum': 5, 155 | 'col': 8, 156 | 'vcol': 0, 157 | }, 158 | ] 159 | assert qf == expected 160 | 161 | ctx.buffer_name = 'myfile.cs' 162 | response = [ 163 | { 164 | 'Message': 'some text', 165 | 'Line': 5, 166 | 'Column': 8, 167 | 'LogLevel': 'Error', 168 | }, 169 | ] 170 | qf = quickfixes_from_response(ctx, response) 171 | expected = [ 172 | { 173 | 'filename': ctx.buffer_name, 174 | 'text': 'some text', 175 | 'lnum': 5, 176 | 'col': 8, 177 | 'vcol': 0, 178 | 'type': 'E', 179 | }, 180 | ] 181 | assert qf == expected 182 | 183 | response = [ 184 | { 185 | 'FileName': 'foo.cs', 186 | 'Text': 'some text', 187 | 'Line': 5, 188 | 'Column': 8, 189 | 'LogLevel': 'Hidden', 190 | }, 191 | ] 192 | qf = quickfixes_from_response(ctx, response) 193 | expected = [ 194 | { 195 | 'filename': 'foo.cs', 196 | 'text': 'some text', 197 | 'lnum': 5, 198 | 'col': 8, 199 | 'vcol': 0, 200 | 'type': 'W', 201 | 'subtype': 'Style', 202 | }, 203 | ] 204 | assert qf == expected 205 | -------------------------------------------------------------------------------- /python/tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = 8 | py38, 9 | lint 10 | 11 | [testenv] 12 | commands = py.test --verbose tests 13 | deps = 14 | pytest 15 | pytest-mock 16 | 17 | [testenv:lint] 18 | basepython=python3.8 19 | deps = 20 | pylint 21 | pycodestyle 22 | pytest 23 | pytest-mock 24 | commands= 25 | pylint -E {envsitepackagesdir}/omnisharp {toxinidir}/tests 26 | pycodestyle {envsitepackagesdir}/omnisharp {toxinidir}/tests 27 | 28 | [testenv:coverage] 29 | basepython=python3.8 30 | deps = 31 | pytest 32 | pytest-mock 33 | pytest-cov 34 | commands = py.test --verbose --cov=omnisharp --cov-report html tests 35 | -------------------------------------------------------------------------------- /rplugin/python3/deoplete/sources/deoplete_OmniSharp.py: -------------------------------------------------------------------------------- 1 | 2 | """ omnisharp source for deoplete """ 3 | import logging 4 | import os 5 | import sys 6 | from os.path import abspath, dirname, exists, join, pardir 7 | import re 8 | 9 | from .base import Base 10 | 11 | # This implementation was based off of the deoplete-lsp deoplete source 12 | # Which is similar in that it calls lua to trigger a request, which receives a callback, 13 | # then re-triggers deoplete autocomplete 14 | class Source(Base): 15 | def __init__(self, vim): 16 | super().__init__(vim) 17 | 18 | self.name = 'omnisharp' 19 | self.mark = '[OS]' 20 | self.rank = 500 21 | self.filetypes = ['cs'] 22 | # This pattern will trigger auto completion even if the typed text has not reached min_pattern_length 23 | self.input_pattern = r'[^. \t0-9]\.\w*' 24 | self.is_volatile = True 25 | self.previousLhs = '' 26 | self.partial = '' 27 | 28 | def parseInput(self, value): 29 | match = re.match(r"^(.*\W)(\w*)$", value) 30 | 31 | if match: 32 | groups = match.groups() 33 | return groups[0], groups[1] 34 | return None, None 35 | 36 | def gather_candidates(self, context): 37 | currentInput = context['input'] 38 | 39 | lhs, partial = self.parseInput(currentInput) 40 | 41 | if lhs is None: 42 | return [] 43 | 44 | if lhs != self.previousLhs or not partial.startswith(self.previousPartial): 45 | self.previousLhs = lhs 46 | self.previousPartial = partial 47 | self.vim.call('deoplete#source#omnisharp#sendRequest', lhs, partial) 48 | return [] 49 | 50 | return self.vim.vars['deoplete#source#omnisharp#_results'] or [] 51 | -------------------------------------------------------------------------------- /syntax/omnisharpdoc.vim: -------------------------------------------------------------------------------- 1 | if exists('b:current_syntax') 2 | finish 3 | endif 4 | 5 | let s:save_cpo = &cpoptions 6 | set cpoptions&vim 7 | 8 | syn include @cs syntax/cs.vim 9 | syn region osdcs start="^\%1l" keepend end="\%1l$" contains=@cs 10 | 11 | syn match osdSection "^##.\+" contains=osdHash 12 | syn match osdHash contained "#" conceal 13 | syn match osdParam "^`[^`]\+`" contains=osdTick 14 | syn match osdTick contained "`" conceal 15 | 16 | hi def link osdSection Statement 17 | hi def link osdParam Comment 18 | 19 | hi def OmniSharpActiveParameter cterm=bold,italic,underline gui=bold,italic,underline 20 | 21 | let b:current_syntax = 'omnisharpdoc' 22 | 23 | let &cpoptions = s:save_cpo 24 | unlet s:save_cpo 25 | 26 | " vim:et:sw=2:sts=2 27 | -------------------------------------------------------------------------------- /syntax/omnisharplog.vim: -------------------------------------------------------------------------------- 1 | if exists('b:current_syntax') 2 | finish 3 | endif 4 | 5 | let s:save_cpo = &cpoptions 6 | set cpoptions&vim 7 | 8 | syn match oslName "^\[\w\{4,5\}\]: .*$"hs=s+7 contains=oslTrace,oslDebug,oslInformation,oslWarning,oslError,oslCritical 9 | 10 | syn match oslTrace "^\[trce\]"ms=s+1,me=e-1 contained 11 | syn match oslDebug "^\[dbug\]"ms=s+1,me=e-1 contained 12 | syn match oslInformation "^\[info\]"ms=s+1,me=e-1 contained 13 | syn match oslWarning "^\[warn\]"ms=s+1,me=e-1 contained 14 | syn match oslError "^\[fail\]"ms=s+1,me=e-1 contained 15 | syn match oslError "^\[ERROR\]"ms=s+1,me=e-1 contained 16 | syn match oslCritical "^\[crit\]"ms=s+1,me=e-1 contained 17 | 18 | syn match oslEndpoint "^Request: .*$"hs=s+9 19 | syn match oslServerEndpoint "^Server \%(Request\|Response\): .*$"hs=s+16 20 | 21 | syn region oslRequestResponse start="\*\{12}\s\+\%(Request\|Response\)\%(\s(.\{-})\)\?\s\+\*\{12}" end="^}" transparent fold 22 | 23 | hi def link oslName Comment 24 | 25 | hi def link oslTrace Identifier 26 | hi def link oslDebug NonText 27 | hi def link oslInformation Type 28 | hi def link oslWarning WarningMsg 29 | hi def link oslError ErrorMsg 30 | hi def link oslCritical ErrorMsg 31 | 32 | hi def link oslEndpoint Identifier 33 | hi def link oslServerEndpoint Constant 34 | 35 | let b:current_syntax = 'omnisharplog' 36 | 37 | let &cpoptions = s:save_cpo 38 | unlet s:save_cpo 39 | 40 | " vim:et:sw=2:sts=2 41 | -------------------------------------------------------------------------------- /syntax_checkers/cs/codecheck.vim: -------------------------------------------------------------------------------- 1 | if !get(g:, 'OmniSharp_loaded') | finish | endif 2 | if !OmniSharp#util#CheckCapabilities() | finish | endif 3 | if exists('g:loaded_syntastic_cs_code_checker') | finish | endif 4 | let g:loaded_syntastic_cs_code_checker = 1 5 | 6 | let s:save_cpo = &cpoptions 7 | set cpoptions&vim 8 | 9 | function! SyntaxCheckers_cs_code_checker_IsAvailable() dict abort 10 | return 1 11 | endfunction 12 | 13 | function! SyntaxCheckers_cs_code_checker_GetLocList() dict abort 14 | if g:OmniSharp_server_stdio 15 | let s:codecheck_pending = 1 16 | call OmniSharp#actions#diagnostics#Check( 17 | \ {_ -> execute('let s:codecheck_pending = 0')}) 18 | let starttime = reltime() 19 | " Syntastic is synchronous so must wait for the callback to be completed. 20 | while s:codecheck_pending && reltime(starttime)[0] < g:OmniSharp_timeout 21 | sleep 50m 22 | endwhile 23 | if s:codecheck_pending | return [] | endif 24 | let loc_list = b:codecheck 25 | else 26 | let loc_list = OmniSharp#actions#diagnostics#Check() 27 | endif 28 | for loc in loc_list 29 | let loc.valid = 1 30 | let loc.bufnr = bufnr('%') 31 | endfor 32 | return loc_list 33 | endfunction 34 | 35 | call g:SyntasticRegistry.CreateAndRegisterChecker({ 36 | \ 'filetype': 'cs', 37 | \ 'name': 'code_checker' 38 | \}) 39 | 40 | let &cpoptions = s:save_cpo 41 | unlet s:save_cpo 42 | 43 | " vim:et:sw=2:sts=2 44 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | ### Running tests 2 | 3 | These tests use the [vader.vim](https://github.com/junegunn/vader.vim) plugin, 4 | which needs to be installed alongside OmniSharp-vim. 5 | 6 | To run a test, open a .vader file and run `:Vader`, or run the following from 7 | the command line: 8 | 9 | ```sh 10 | vim -u vimrc -c 'Vader! testfile.vader' 11 | ``` 12 | 13 | To run all tests, run this command line: 14 | 15 | ```sh 16 | vim -u vimrc -c 'Vader! *' 17 | ``` 18 | -------------------------------------------------------------------------------- /test/codeformat.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | public class Test { 6 | 7 | } 8 | 9 | Execute (run code format): 10 | call OmniSharpTestInitializeBuffer('CodeFormat') 11 | call OmniSharpWarmup('OmniSharp#actions#format#Format', []) 12 | call OmniSharpTestAwait('OmniSharp#actions#format#Format', []) 13 | 14 | Expect cs(should format document): 15 | public class Test 16 | { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /test/complete.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | usi 6 | 7 | Execute (): 8 | " Need to set a filename for OmniSharp-roslyn 9 | call OmniSharpTestInitializeBuffer('Complete') 10 | call OmniSharpWarmup('OmniSharp#actions#complete#Get', ['usi']) 11 | 12 | Do (invoke omnicomplete on 'usi'): 13 | A\\ 14 | 15 | Expect cs(should complete word): 16 | using 17 | -------------------------------------------------------------------------------- /test/example/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin/ 3 | obj/ 4 | -------------------------------------------------------------------------------- /test/example/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace example 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | Console.WriteLine("Hello World!"); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/example/example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/example/example.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example", "example.csproj", "{A1465805-934B-4ECC-92AD-95C326A4EB02}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(SolutionProperties) = preSolution 14 | HideSolutionNode = FALSE 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {A1465805-934B-4ECC-92AD-95C326A4EB02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {A1465805-934B-4ECC-92AD-95C326A4EB02}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {A1465805-934B-4ECC-92AD-95C326A4EB02}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {A1465805-934B-4ECC-92AD-95C326A4EB02}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /test/example/omnisharp.json: -------------------------------------------------------------------------------- 1 | { 2 | "FormattingOptions": { 3 | "EnableEditorConfigSupport": false, 4 | "NewLine": "\n", 5 | "UseTabs": false, 6 | "TabSize": 4, 7 | "IndentationSize": 4, 8 | "SpacingAfterMethodDeclarationName": false, 9 | "SpaceWithinMethodDeclarationParenthesis": false, 10 | "SpaceBetweenEmptyMethodDeclarationParentheses": false, 11 | "SpaceAfterMethodCallName": false, 12 | "SpaceWithinMethodCallParentheses": false, 13 | "SpaceBetweenEmptyMethodCallParentheses": false, 14 | "SpaceAfterControlFlowStatementKeyword": true, 15 | "SpaceWithinExpressionParentheses": false, 16 | "SpaceWithinCastParentheses": false, 17 | "SpaceWithinOtherParentheses": false, 18 | "SpaceAfterCast": false, 19 | "SpacesIgnoreAroundVariableDeclaration": false, 20 | "SpaceBeforeOpenSquareBracket": false, 21 | "SpaceBetweenEmptySquareBrackets": false, 22 | "SpaceWithinSquareBrackets": false, 23 | "SpaceAfterColonInBaseTypeDeclaration": true, 24 | "SpaceAfterComma": true, 25 | "SpaceAfterDot": false, 26 | "SpaceAfterSemicolonsInForStatement": true, 27 | "SpaceBeforeColonInBaseTypeDeclaration": true, 28 | "SpaceBeforeComma": false, 29 | "SpaceBeforeDot": false, 30 | "SpaceBeforeSemicolonsInForStatement": false, 31 | "SpacingAroundBinaryOperator": "single", 32 | "IndentBraces": false, 33 | "IndentBlock": true, 34 | "IndentSwitchSection": true, 35 | "IndentSwitchCaseSection": true, 36 | "IndentSwitchCaseSectionWhenBlock": true, 37 | "LabelPositioning": "oneLess", 38 | "WrappingPreserveSingleLine": true, 39 | "WrappingKeepStatementsOnSingleLine": true, 40 | "NewLinesForBracesInTypes": true, 41 | "NewLinesForBracesInMethods": true, 42 | "NewLinesForBracesInProperties": true, 43 | "NewLinesForBracesInAccessors": true, 44 | "NewLinesForBracesInAnonymousMethods": true, 45 | "NewLinesForBracesInControlBlocks": true, 46 | "NewLinesForBracesInAnonymousTypes": true, 47 | "NewLinesForBracesInObjectCollectionArrayInitializers": true, 48 | "NewLinesForBracesInLambdaExpressionBody": true, 49 | "NewLineForElse": true, 50 | "NewLineForCatch": true, 51 | "NewLineForFinally": true, 52 | "NewLineForMembersInObjectInit": true, 53 | "NewLineForMembersInAnonymousTypes": true, 54 | "NewLineForClausesInQuery": true 55 | }, 56 | "RoslynExtensionsOptions": { 57 | "DocumentAnalysisTimeoutMS": 500, 58 | "EnableAnalyzersSupport": false, 59 | "EnableDecompilationSupport": false, 60 | "EnableImportCompletion": false 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/fixusings.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | using System; 6 | public class Test 7 | { 8 | 9 | } 10 | 11 | Execute (run fix usings): 12 | call OmniSharpTestInitializeBuffer('FixUsings1') 13 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 14 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 15 | 16 | Expect cs(should remove unused using): 17 | public class Test 18 | { 19 | 20 | } 21 | 22 | 23 | Given cs(): 24 | public class Test 25 | { 26 | public Test() 27 | { 28 | Console.WriteLine("test"); 29 | } 30 | } 31 | 32 | Execute (run fix usings): 33 | call OmniSharpTestInitializeBuffer('FixUsings2') 34 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 35 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 36 | 37 | Expect cs(should add required using): 38 | using System; 39 | 40 | public class Test 41 | { 42 | public Test() 43 | { 44 | Console.WriteLine("test"); 45 | } 46 | } 47 | 48 | 49 | Given cs(): 50 | using System; 51 | 52 | public class Test 53 | { 54 | public Test() 55 | { 56 | Console.WriteLine(Encoding.UTF8.ToString()); 57 | } 58 | } 59 | 60 | Execute (run fix usings): 61 | call OmniSharpTestInitializeBuffer('FixUsings3') 62 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 63 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 64 | 65 | Expect cs(should add another required using): 66 | using System; 67 | using System.Text; 68 | 69 | public class Test 70 | { 71 | public Test() 72 | { 73 | Console.WriteLine(Encoding.UTF8.ToString()); 74 | } 75 | } 76 | 77 | 78 | Given cs(): 79 | using System; 80 | 81 | public class Test 82 | { 83 | public Test() 84 | { 85 | Console.WriteLine(Encoding.UTF8.ToString()); 86 | } 87 | } 88 | 89 | Execute (run fix usings with virtualedit=all): 90 | call OmniSharpTestInitializeBuffer('FixUsings4') 91 | set virtualedit=all 92 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 93 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 94 | 95 | Expect cs(should add another required using): 96 | using System; 97 | using System.Text; 98 | 99 | public class Test 100 | { 101 | public Test() 102 | { 103 | Console.WriteLine(Encoding.UTF8.ToString()); 104 | } 105 | } 106 | 107 | 108 | Given cs(): 109 | using System; 110 | 111 | using System.Text; 112 | 113 | public class Test 114 | { 115 | public Test() 116 | { 117 | Console.WriteLine(Encoding.UTF8.ToString()); 118 | Console.WriteLine(DateTime.Parse("1999-01-01T00:01:01Z", CultureInfo.InvariantCulture)); 119 | } 120 | } 121 | 122 | Execute (run fix usings with empty line and virtualedit=): 123 | call OmniSharpTestInitializeBuffer('FixUsings4') 124 | set virtualedit= 125 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 126 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 127 | 128 | Expect cs(should add another required using between the others): 129 | using System; 130 | using System.Globalization; 131 | using System.Text; 132 | 133 | public class Test 134 | { 135 | public Test() 136 | { 137 | Console.WriteLine(Encoding.UTF8.ToString()); 138 | Console.WriteLine(DateTime.Parse("1999-01-01T00:01:01Z", CultureInfo.InvariantCulture)); 139 | } 140 | } 141 | 142 | 143 | Given cs(): 144 | using System; 145 | 146 | using System.Text; 147 | 148 | public class Test 149 | { 150 | public Test() 151 | { 152 | Console.WriteLine(Encoding.UTF8.ToString()); 153 | Console.WriteLine(DateTime.Parse("1999-01-01T00:01:01Z", CultureInfo.InvariantCulture)); 154 | } 155 | } 156 | 157 | Execute (run fix usings with empty line and virtualedit=all): 158 | call OmniSharpTestInitializeBuffer('FixUsings4') 159 | set virtualedit=all 160 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 161 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 162 | 163 | Expect cs(should add another required using between the others): 164 | using System; 165 | using System.Globalization; 166 | using System.Text; 167 | 168 | public class Test 169 | { 170 | public Test() 171 | { 172 | Console.WriteLine(Encoding.UTF8.ToString()); 173 | Console.WriteLine(DateTime.Parse("1999-01-01T00:01:01Z", CultureInfo.InvariantCulture)); 174 | } 175 | } 176 | 177 | 178 | Given cs(): 179 | public class test { 180 | class1 ns1 = new class1(); 181 | } 182 | 183 | namespace ns1 184 | { 185 | public class class1{} 186 | } 187 | 188 | namespace ns2 189 | { 190 | public class class1{} 191 | } 192 | 193 | Execute (run fix usings): 194 | call OmniSharpTestInitializeBuffer('FixUsings5') 195 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 196 | call OmniSharpTestAwait('OmniSharp#actions#usings#Fix', []) 197 | 198 | Expect cs(should not add ambiguous using): 199 | public class test { 200 | class1 ns1 = new class1(); 201 | } 202 | 203 | namespace ns1 204 | { 205 | public class class1{} 206 | } 207 | 208 | namespace ns2 209 | { 210 | public class class1{} 211 | } 212 | 213 | Execute (should return ambiguous usings to Callback): 214 | call OmniSharpTestInitializeBuffer('FixUsings6') 215 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 216 | let g:OmniSharp_test_locations = [] 217 | function! s:CallbackFixUsings(locations) 218 | let g:OmniSharp_test_waiting = 0 219 | let g:OmniSharp_test_locations = a:locations 220 | endfunction 221 | let Callback = function('s:CallbackFixUsings') 222 | let g:OmniSharp_test_waiting = 1 223 | call function('OmniSharp#actions#usings#Fix', [Callback])() 224 | let starttime = reltime() 225 | while g:OmniSharp_test_waiting 226 | \ && reltime(starttime)[0] < g:OmniSharp_test_timeout 227 | sleep 50m 228 | endwhile 229 | AssertEqual len(getqflist()), 0 230 | Assert !g:OmniSharp_test_waiting, 'OmniSharp#actions#usings#Fix timed out' 231 | AssertEqual len(g:OmniSharp_test_locations), 2 232 | AssertEqual g:OmniSharp_test_locations[0].lnum, 2 233 | 234 | Execute (should add ambiguous usings to quickfix): 235 | call OmniSharpTestInitializeBuffer('FixUsings7') 236 | call OmniSharpWarmup('OmniSharp#actions#usings#Fix', []) 237 | " Cannot use OmniSharpTestAwait, as the callback prevents the default quickfix 238 | " behaviour 239 | call OmniSharp#actions#usings#Fix() 240 | sleep 5 241 | AssertEqual len(getqflist()), 2 242 | cfirst 243 | AssertEqual line('.'), 2 244 | -------------------------------------------------------------------------------- /test/gotodefinition.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | public class Test 6 | { 7 | int i; 8 | public Test() 9 | { 10 | i = 0; 11 | } 12 | 13 | } 14 | 15 | Execute (go to definition): 16 | call OmniSharpTestInitializeBuffer('GotoDefinition') 17 | call search("i = 0") 18 | " Cannot use OmniSharpTestAwait, as the callback prevents the default 19 | " navigation behaviour 20 | call OmniSharp#actions#definition#Find() 21 | sleep 5 22 | AssertEqual 3, line(".") 23 | -------------------------------------------------------------------------------- /test/gotometadata.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | using System.IO; 6 | 7 | public class Test 8 | { 9 | MemoryStream stream; 10 | } 11 | 12 | Execute (go to metadata preview): 13 | call OmniSharpTestInitializeBuffer('GotoMetadata1') 14 | call search("MemoryStream stream") 15 | " Cannot use OmniSharpTestAwait, as the callback prevents the default preview 16 | " behaviour 17 | call OmniSharp#actions#definition#Preview() 18 | sleep 5 19 | wincmd p 20 | AssertEqual 'MemoryStream.cs', expand('%:t') 21 | pclose 22 | 23 | Given cs(): 24 | using System.IO; 25 | 26 | public class Test 27 | { 28 | MemoryStream stream; 29 | } 30 | 31 | Execute (go to metadata window): 32 | call OmniSharpTestInitializeBuffer('GotoMetadata2') 33 | call search("MemoryStream stream") 34 | " Cannot use OmniSharpTestAwait, as the callback prevents the default 35 | " navigation behaviour 36 | call OmniSharp#actions#definition#Find() 37 | sleep 5 38 | AssertEqual 'MemoryStream.cs', expand('%:t') 39 | -------------------------------------------------------------------------------- /test/rename.vader: -------------------------------------------------------------------------------- 1 | Include: utils/startserver.vader 2 | Include: utils/async-helper.vader 3 | 4 | Given cs(): 5 | public class TestRenameTo 6 | { 7 | public TestRenameTo() 8 | { 9 | } 10 | } 11 | 12 | Execute (rename constructor): 13 | call OmniSharpTestInitializeBuffer('RenameTo') 14 | call search('TestRenameTo()') 15 | call OmniSharpTestAwait('OmniSharp#actions#rename#To', ['Renamed']) 16 | 17 | Expect cs(should rename class): 18 | public class Renamed 19 | { 20 | public Renamed() 21 | { 22 | } 23 | } 24 | 25 | Given cs(): 26 | public class TestOmdøbAnother 27 | { 28 | public TestOmdøbAnother() 29 | { 30 | } 31 | } 32 | 33 | Execute (rename after multi-byte characters): 34 | call OmniSharpTestInitializeBuffer('RenameAnother') 35 | call search('TestOmdøbAnother\ze()', 'e') 36 | call OmniSharpTestAwait('OmniSharp#actions#rename#To', ['RenamedAnother']) 37 | 38 | Expect cs(should rename class): 39 | public class RenamedAnother 40 | { 41 | public RenamedAnother() 42 | { 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/run-async.vader: -------------------------------------------------------------------------------- 1 | Execute (Test neovim jobs): 2 | let command = ['bash', '-c', 'exit 133'] 3 | let jobstatus = 0 4 | if OmniSharp#proc#supportsNeovimJobs() 5 | let job = OmniSharp#proc#neovimJobStart(command) 6 | Assert job.job_id > 0, "Could not launch the specified command" 7 | let jobstatus = jobwait([job.job_id])[0] 8 | AssertEqual 133, jobstatus 9 | endif 10 | 11 | Execute (Test vim jobs): 12 | let command = ['bash', '-c', 'exit 133'] 13 | let jobstatus = 0 14 | if OmniSharp#proc#supportsVimJobs() 15 | let job = OmniSharp#proc#vimJobStart(command) 16 | while job_info(job.job_id).status != 'dead' 17 | sleep 10 m 18 | endwhile 19 | sleep 10 m 20 | let jobstatus = job_info(job.job_id).exitval 21 | AssertEqual 133, jobstatus 22 | endif 23 | 24 | Execute (Test vim-dispatch jobs): 25 | let command = ['bash', '-c', 'exit 133'] 26 | if OmniSharp#proc#supportsVimDispatch() 27 | let request = OmniSharp#proc#dispatchStart(command) 28 | call dispatch#complete(request) 29 | AssertNotEqual 0, request.pid 30 | endif 31 | 32 | Execute (Test vimproc jobs): 33 | let command = ['bash', '-c', 'exit 133'] 34 | if OmniSharp#proc#supportsVimProc() 35 | let proc = OmniSharp#proc#vimprocStart(command) 36 | call proc.waitpid() 37 | AssertEqual 133, result.status 38 | endif 39 | -------------------------------------------------------------------------------- /test/utils/async-helper.vader: -------------------------------------------------------------------------------- 1 | After(): 2 | call OmniSharpTestCleanupBuffer() 3 | 4 | Execute (set up async helper): 5 | function! s:CallbackStopWaiting(...) 6 | let g:OmniSharp_test_waiting = 0 7 | endfunction 8 | 9 | function! OmniSharpWarmup(funcname, args) abort 10 | call OmniSharpTestAwait(a:funcname, a:args, 1) 11 | endfunction 12 | 13 | function! OmniSharpTestAwait(funcname, args, ...) abort 14 | let warmup = a:0 ? a:1 : 0 15 | let g:OmniSharp_test_waiting = 1 16 | call function(a:funcname, a:args + [function('s:CallbackStopWaiting')])() 17 | let starttime = reltime() 18 | while g:OmniSharp_test_waiting 19 | \ && reltime(starttime)[0] < g:OmniSharp_test_timeout 20 | sleep 50m 21 | endwhile 22 | if !warmup 23 | Assert !g:OmniSharp_test_waiting, a:funcname . ' timed out' 24 | endif 25 | endfunction 26 | 27 | function! OmniSharpTestInitializeBuffer(filename) abort 28 | " Need to set a filename for OmniSharp-roslyn 29 | execute printf('file example/%s.cs', a:filename) 30 | set buftype= 31 | if has_key(b:, 'OmniSharp_UpdateChangeTick') 32 | unlet b:OmniSharp_UpdateChangeTick 33 | endif 34 | let opts = { 35 | \ 'Callback': function('s:CallbackStopWaiting'), 36 | \ 'SendBuffer': 1 37 | \} 38 | call OmniSharpTestAwait('OmniSharp#actions#buffer#Update', [opts]) 39 | endfunction 40 | 41 | function! OmniSharpTestCleanupBuffer() abort 42 | set buftype=nofile 43 | endfunction 44 | -------------------------------------------------------------------------------- /test/utils/startserver.vader: -------------------------------------------------------------------------------- 1 | Execute (start server): 2 | let g:OmniSharp_test_timeout = get(g:, 'OmniSharp_test_timeout', 10) 3 | edit! example/Program.cs 4 | let host = OmniSharp#GetHost() 5 | let job = OmniSharp#proc#GetJob(host.sln_or_dir) 6 | while reltime(job.start_time)[0] < g:OmniSharp_test_timeout && !job.loaded 7 | sleep 50m 8 | endwhile 9 | Assert job.loaded, 'Timed out waiting for job to load' 10 | -------------------------------------------------------------------------------- /test/vimrc: -------------------------------------------------------------------------------- 1 | if &compatible 2 | set nocompatible 3 | endif 4 | 5 | filetype off 6 | 7 | " Assuming that plugins are installed in the same folder, e.g. ~/.vim/plugged 8 | let omnisharpdir = expand("\:h:h") 9 | let plugindir = fnamemodify(omnisharpdir, ':h') 10 | 11 | " Dependency to vader.vim 12 | let &runtimepath .= ',' . plugindir . '/vader.vim' 13 | let &runtimepath .= ',' . omnisharpdir 14 | 15 | filetype plugin indent on 16 | syntax on 17 | set cmdheight=3 18 | 19 | let g:OmniSharp_server_stdio = 1 20 | let g:OmniSharp_server_use_net6 = 1 21 | let g:OmniSharp_start_without_solution = 1 22 | let g:OmniSharp_highlighting = 0 23 | let g:OmniSharp_selector_ui = '' 24 | let g:OmniSharp_open_quickfix = 0 25 | let g:OmniSharp_loglevel = 'none' 26 | 27 | let g:OmniSharp_popup = 0 28 | let g:OmniSharp_test_timeout = 10 29 | --------------------------------------------------------------------------------