Skip to content

Commit

Permalink
Update tracked files on server start
Browse files Browse the repository at this point in the history
Closes #7

Ues s:file_versions to know which files have a didOpen sent to the
server. When the server is started all files need to get resent as a
didOpen so that didChange can be used again. Since there are two paths
to trigger a didOpen - already open file when the server starts or a
newly opened buffer - only send didOpen for the files which are not
present in s:file_versions.

- Add lsc#file#trackAll to iterate over buffers of a given filetype and
  send didOpen for each.
- Add lsc#files#clean to mark all files of a filetype as untracked
- Only send didOpen if the file is not already tracked
- Only send didChange if the file is tracked
- Add lsc#file#version to get the file version for the current buffer.
  Could be useful for a status line.
- Add a boolean return from RunCommand so lsc#file#trackAll can be
  called only when the server is actually started.
- Add an optional file_path argument to lsc#util#documentUri since the
  file for didOpen isn't necessarily the current buffer anymore
  • Loading branch information
natebosch committed Jun 4, 2017
1 parent 36b1320 commit 31a6e93
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 23 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 0.2.1-dev

- Clean up local state when a language server exits.
- Handle language server restarts:
- Clean up local state when a language server exits.
- Call `didOpen` for all open files when a language server (re)starts.

# 0.2.0

Expand Down
60 changes: 45 additions & 15 deletions autoload/lsc/file.vim
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
if !exists('s:initialized')
" file path -> file version
let s:file_versions = {}
endif

" Send a 'didOpen' message for all open files of type `filetype` if they aren't
" already tracked.
function! lsc#file#trackAll(filetype) abort
for buffer in getbufinfo({'loaded': v:true})
if getbufvar(buffer.bufnr, '&filetype') != a:filetype | continue | endif
call s:DidOpen(buffer.name)
endfor
endfunction

" Run language servers for this filetype if they aren't already running and send
" the 'didOpen' message.
function! lsc#file#onOpen() abort
call lsc#server#start(&filetype)
let file_path = expand('%:p')
let buffer_content = join(getline(1, '$'), "\n")
call s:DidOpen(expand('%:p'))
endfunction

" Send the 'didOpen' message for a file if it isn't already tracked.
function! s:DidOpen(file_path) abort
if has_key(s:file_versions, a:file_path) | return | endif
let bufnr = bufnr(a:file_path)
if !bufloaded(bufnr) | return | endif
let s:file_versions[a:file_path] = 1
let buffer_content = join(getbufline(bufnr, 1, '$'), "\n")
let filetype = getbufvar(bufnr, '&filetype')
let params = {'textDocument':
\ {'uri': lsc#util#documentUri(),
\ 'languageId': &filetype,
\ 'version': <SID>FileVersion(file_path),
\ {'uri': lsc#util#documentUri(a:file_path),
\ 'languageId': filetype,
\ 'version': s:file_versions[a:file_path],
\ 'text': buffer_content
\ }
\ }
call lsc#server#call(&filetype, 'textDocument/didOpen', params)
call lsc#server#call(filetype, 'textDocument/didOpen', params)
endfunction

" Mark all files of type `filetype` as untracked.
function! lsc#file#clean(filetype) abort
for buffer in getbufinfo({'loaded': v:true})
if getbufvar(buffer.bufnr, '&filetype') != a:filetype | continue | endif
if has_key(s:file_versions, buffer.name)
unlet s:file_versions[buffer.name]
endif
endfor
endfunction

function! lsc#file#onChange() abort
Expand All @@ -27,24 +60,21 @@ function! lsc#file#flushChanges(...) abort
if !exists('b:lsc_flush_timer')
return
endif
let file_path = expand('%:p')
if !has_key(s:file_versions, file_path) | return | endif
let s:file_versions[file_path] += 1
call timer_stop(b:lsc_flush_timer)
unlet b:lsc_flush_timer
let file_path = expand('%:p')
let buffer_content = join(getline(1, '$'), "\n")
let params = {'textDocument':
\ {'uri': lsc#util#documentUri(),
\ 'version': <SID>FileVersion(file_path),
\ 'version': s:file_versions[file_path],
\ },
\ 'contentChanges': [{'text': buffer_content}],
\ }
call lsc#server#call(&filetype, 'textDocument/didChange', params)
endfunction

" file path -> file version
let s:file_versions = {}

" A monotonically increasing number for each open file.
function! s:FileVersion(file_path)
let s:file_versions[a:file_path] = get(s:file_versions, a:file_path, 0) + 1
return s:file_versions[a:file_path]
function! lsc#file#version() abort
return get(s:file_versions, expand('%:p'), '')
endfunction
16 changes: 11 additions & 5 deletions autoload/lsc/server.vim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ if !exists('s:initialized')
endif

function! lsc#server#start(filetype) abort
call <SID>RunCommand(g:lsc_server_commands[a:filetype])
if <SID>RunCommand(g:lsc_server_commands[a:filetype])
call lsc#file#trackAll(a:filetype)
endif
endfunction

function! lsc#server#kill(file_type) abort
Expand Down Expand Up @@ -54,11 +56,13 @@ function! lsc#server#setBuffer(ch_id, message) abort
let s:channel_buffers[a:ch_id] = a:message
endfunction

" Start a language server using `command` if it isn't already running.
"
" Returns v:true if the server was started, or v:false if it was already
" running.
function! s:RunCommand(command) abort
if has_key(s:running_servers, a:command)
" Server is already running
return
endif
if has_key(s:running_servers, a:command) | return v:false | endif

let job_options = {'in_io': 'pipe', 'in_mode': 'raw',
\ 'out_io': 'pipe', 'out_mode': 'raw',
\ 'out_cb': 'lsc#server#channelCallback', 'exit_cb': 'lsc#server#onExit'}
Expand All @@ -85,6 +89,7 @@ function! s:RunCommand(command) abort
\}
call lsc#server#call(&filetype, 'initialize',
\ params, data.onInitialize, v:true)
return v:true
endfunction

" Find the command for `job` and clean up it's state
Expand All @@ -111,6 +116,7 @@ function! s:OnCommandExit(command) abort
if g:lsc_server_commands[filetype] != a:command | continue | endif
call lsc#complete#clean(filetype)
call lsc#diagnostics#clean(filetype)
call lsc#file#clean(filetype)
endfor
endfunction

Expand Down
9 changes: 7 additions & 2 deletions autoload/lsc/util.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ function! lsc#util#winDo(command) abort
execute 'keepjumps noautocmd '.current_window.'wincmd w'
endfunction

function! lsc#util#documentUri() abort
return 'file://'.expand('%:p')
function! lsc#util#documentUri(...) abort
if a:0 >= 1
let file_path = a:1
else
let file_path = expand('%:p')
endif
return 'file://'.file_path
endfunction

function! lsc#util#documentPath(uri) abort
Expand Down

0 comments on commit 31a6e93

Please sign in to comment.