function! s:open_location(path, line, col, ...) abort normal! m' let l:mods = a:0 ? a:1 : '' let l:buffer = bufnr(a:path) if l:mods ==# '' && &modified && !&hidden && l:buffer != bufnr('%') let l:mods = &splitbelow ? 'rightbelow' : 'leftabove' endif if l:mods ==# '' if l:buffer == bufnr('%') let l:cmd = '' else let l:cmd = (l:buffer !=# -1 ? 'b ' . l:buffer : 'edit ' . fnameescape(a:path)) . ' | ' endif else let l:cmd = l:mods . ' ' . (l:buffer !=# -1 ? 'sb ' . l:buffer : 'split ' . fnameescape(a:path)) . ' | ' endif execute l:cmd . 'call cursor('.a:line.','.a:col.')' endfunction " @param location = { " 'filename', " 'lnum', " 'col', " } function! lsp#utils#location#_open_vim_list_item(location, mods) abort call s:open_location(a:location['filename'], a:location['lnum'], a:location['col'], a:mods) endfunction " @params {location} = { " 'uri': 'file://....', " 'range': { " 'start': { 'line': 1, 'character': 1 }, " 'end': { 'line': 1, 'character': 1 }, " } " } function! lsp#utils#location#_open_lsp_location(location) abort let l:path = lsp#utils#uri_to_path(a:location['uri']) let l:bufnr = bufnr(l:path) let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['start']) let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['end']) call s:open_location(l:path, l:start_line, l:start_col) normal! V call setpos("'<", [l:bufnr, l:start_line, l:start_col]) call setpos("'>", [l:bufnr, l:end_line, l:end_col]) endfunction " @param loc = Location | LocationLink " @param cache = {} empty dict " @returns { " 'filename', " 'lnum', " 'col', " 'text', " 'viewstart?', " 'viewend?', " } function! s:lsp_location_item_to_vim(loc, cache) abort if has_key(a:loc, 'targetUri') " LocationLink let l:uri = a:loc['targetUri'] let l:range = a:loc['targetSelectionRange'] let l:use_link = 1 else " Location let l:uri = a:loc['uri'] let l:range = a:loc['range'] let l:use_link = 0 endif if !lsp#utils#is_file_uri(l:uri) return v:null endif let l:path = lsp#utils#uri_to_path(l:uri) let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:range['start']) let l:index = l:line - 1 if has_key(a:cache, l:path) let l:text = a:cache[l:path][l:index] else let l:contents = getbufline(l:path, 1, '$') if !empty(l:contents) let l:text = get(l:contents, l:index, '') else let l:contents = readfile(l:path) let a:cache[l:path] = l:contents let l:text = get(l:contents, l:index, '') endif endif if l:use_link " viewstart/end decremented to account for incrementing in _lsp_to_vim return { \ 'filename': l:path, \ 'lnum': l:line, \ 'col': l:col, \ 'text': l:text, \ 'viewstart': lsp#utils#position#lsp_to_vim(l:path, a:loc['targetRange']['start'])[0] - 1, \ 'viewend': lsp#utils#position#lsp_to_vim(l:path, a:loc['targetRange']['end'])[0] - 1, \ } else return { \ 'filename': l:path, \ 'lnum': l:line, \ 'col': l:col, \ 'text': l:text, \ } endif endfunction " @summary Use this to convert loc to vim list that is compatible with " quickfix and locllist items " @param loc = v:null | Location | Location[] | LocationLink " @returns [] function! lsp#utils#location#_lsp_to_vim_list(loc) abort let l:result = [] let l:cache = {} if empty(a:loc) " v:null return l:result elseif type(a:loc) == type([]) " Location[] for l:location in a:loc let l:vim_loc = s:lsp_location_item_to_vim(l:location, l:cache) if !empty(l:vim_loc) " https:// uri will return empty call add(l:result, l:vim_loc) endif endfor else " Location or LocationLink let l:vim_loc = s:lsp_location_item_to_vim(a:loc, l:cache) if !empty(l:vim_loc) " https:// uri will return empty call add(l:result, l:vim_loc) endif endif return l:result endfunction