Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 72 additions & 17 deletions autoload/youcompleteme.vim
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,38 @@ function! s:OnFileSave()
py3 ycm_state.OnFileSave( vimsupport.GetIntValue( 'buffer_number' ) )
endfunction

function! youcompleteme#EnableFormatOnSaveForThisBuffer()
let b:ycm_format_on_save = 1
autocmd BufWritePost,FileWritePost <buffer>
\ call youcompleteme#FormatPreFileSave()
endfunction

function! youcompleteme#FormatPreFileSave()
" TODO: For the file version, we should use the '[,'] range
if !s:AllowedToCompleteInCurrentBuffer()
return
endif

if !get(b:, 'ycm_completing')
return
endif

if !get(b:, 'ycm_format_on_save', get(g:, 'ycm_format_on_save', 0))
return
endif

if !has_key(b:, 'ycm_format_supported')
let cmds = youcompleteme#GetDefinedSubcommands()
let b:ycm_format_supported = index( cmds, 'Format' ) >= 0
endif

if !b:ycm_format_supported
return
endif

YcmCompleter Format
endfunction


function! s:AbortAutohoverRequest() abort
if g:ycm_auto_hover ==# 'CursorHold' && s:enable_hover
Expand Down Expand Up @@ -1407,6 +1439,7 @@ function! s:SetUpCommands()
\ <line2>,
\ <f-args>)
command! YcmDiags call s:ShowDiagnostics()
command! -nargs=* YcmClearDiags call s:ClearDiagnostics( <f-args> )
command! -nargs=? YcmShowDetailedDiagnostic
\ call s:ShowDetailedDiagnostic( <f-args> )
command! YcmForceCompileAndDiagnostics call s:ForceCompileAndDiagnostics()
Expand Down Expand Up @@ -1466,12 +1499,12 @@ function! youcompleteme#GetCommandResponse( ... ) abort
endfunction


function! s:GetCommandResponseAsyncImpl( callback, origin, ... ) abort
function! s:GetCommandResponseAsyncImpl( callback, origin, resp_type, ... ) abort
let request_id = py3eval(
\ 'ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) )' )

let s:pollers.command.requests[ request_id ] = {
\ 'response_func': 'StringResponse',
\ 'response_func': a:resp_type,
\ 'origin': a:origin,
\ 'callback': a:callback
\ }
Expand All @@ -1493,7 +1526,8 @@ function! youcompleteme#GetCommandResponseAsync( callback, ... ) abort
return
endif

call s:GetCommandResponseAsyncImpl( callback, 'extern', a:000 )
call call('s:GetCommandResponseAsyncImpl',
\ [ a:callback, 'extern', 'StringResponse' ] + a:000 )
endfunction


Expand All @@ -1508,18 +1542,8 @@ function! youcompleteme#GetRawCommandResponseAsync( callback, ... ) abort
return
endif

let request_id = py3eval(
\ 'ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) )' )

let s:pollers.command.requests[ request_id ] = {
\ 'response_func': 'Response',
\ 'origin': 'extern_raw',
\ 'callback': a:callback
\ }
if s:pollers.command.id == -1
let s:pollers.command.id = timer_start( s:pollers.command.wait_milliseconds,
\ function( 's:PollCommands' ) )
endif
call call( 's:GetCommandResponseAsyncImpl',
\ [ a:callback, 'extern_raw', 'Response' ] + a:000 )
endfunction


Expand Down Expand Up @@ -1599,6 +1623,19 @@ function! youcompleteme#OpenGoToList()
endfunction


function! s:ClearDiagnostics( ... ) abort
if index( a:000, 'all' ) >= 0
" Clear diagnostics for all buffers
py3 <<trim EOF
for buf in vim.buffers:
ycm_state.ClearDiagnosticsUI( buffer.numer )
EOF
else
py3 ycm_state.ClearDiagnosticsUI( vim.current.buffer.number )
endif
endfunction


function! s:ShowDiagnostics()
py3 ycm_state.ShowDiagnostics()
endfunction
Expand Down Expand Up @@ -1657,6 +1694,7 @@ if exists( '*popup_atcursor' )
call s:GetCommandResponseAsyncImpl(
\ function( 's:ShowHoverResult' ),
\ 'autohover',
\ 'Response',
\ b:ycm_hover.command )
endif
endfunction
Expand All @@ -1669,12 +1707,27 @@ if exists( '*popup_atcursor' )
return
endif

let l:syntax = b:ycm_hover.syntax
if type( a:response ) == v:t_dict
if has_key( a:response, 'detailed_info' )
let response = a:response.detailed_info
elseif has_key( a:response, 'message' )
let response = a:response.message
endif

if has_key( a:response, 'filetype' )
let l:syntax = a:response.filetype
endif
else
let response = string(a:response)
endif

" Try to position the popup at the cursor, but avoid wrapping. If the
" longest line is > screen width (&columns), then we just have to wrap, and
" place the popup at the leftmost column.
"
" Find the longest line (FIXME: probably doesn't work well for multi-byte)
let lines = split( a:response, "\n" )
let lines = split( response, "\n" )
let len = max( map( copy( lines ), "len( v:val )" ) )

let wrap = 0
Expand All @@ -1696,6 +1749,7 @@ if exists( '*popup_atcursor' )
\ 'maxwidth': &columns,
\ 'close': 'click',
\ 'fixed': 0,
\ 'scrollbar': 1,
\ }

if has_key( b:ycm_hover, 'popup_params' )
Expand All @@ -1704,9 +1758,10 @@ if exists( '*popup_atcursor' )
endif

let s:cursorhold_popup = popup_atcursor( lines, popup_params )

call setbufvar( winbufnr( s:cursorhold_popup ),
\ '&syntax',
\ b:ycm_hover.syntax )
\ l:syntax )
endfunction


Expand Down
2 changes: 2 additions & 0 deletions plugin/youcompleteme.vim
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ let g:ycm_echo_current_diagnostic =
\ get( g:, 'ycm_echo_current_diagnostic',
\ get( g:, 'syntastic_echo_current_error', 1 ) )

let g:ycm_echo_all_diagnostics = get( g:, 'ycm_echo_all_diagnostics', 0 )

let g:ycm_filter_diagnostics =
\ get( g:, 'ycm_filter_diagnostics', {} )

Expand Down
10 changes: 6 additions & 4 deletions python/ycm/client/command_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ def StringResponse( self ):
if self._response is None:
return ""

# If not a dictionary or a list, the response is necessarily a
# If not a dictionary, the response is necessarily a
# scalar: boolean, number, string, etc. In this case, we print
# it to the user.
if not isinstance( self._response, ( dict, list ) ):
if not isinstance( self._response, dict ):
return str( self._response )

if 'message' in self._response:
Expand Down Expand Up @@ -211,8 +211,10 @@ def _HandleMessageResponse( self ):


def _HandleDetailedInfoResponse( self, modifiers ):
vimsupport.WriteToPreviewWindow( self._response[ 'detailed_info' ],
modifiers )
vimsupport.WriteToPreviewWindow(
self._response[ 'detailed_info' ],
modifiers,
syntax = self._response.get( 'filetype' ) )


def SendCommandRequestAsync( arguments,
Expand Down
12 changes: 11 additions & 1 deletion python/ycm/client/messages_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.

from ycm.client.base_request import BaseRequest, BuildRequestData
from ycm.vimsupport import PostVimMessage
from ycm.vimsupport import PostVimMessage, ReplaceChunks

import logging

Expand Down Expand Up @@ -81,6 +81,16 @@ def _HandlePollResponse( response, diagnostics_handler ):
diagnostics_handler.UpdateWithNewDiagnosticsForFile(
notification[ 'filepath' ],
notification[ 'diagnostics' ] )
elif 'fixits' in notification:
file_list = set()
for fixit in notification[ 'fixits' ]:
_, files_updated = ReplaceChunks(
chunks = fixit[ 'chunks' ],
silent = True )
file_list.update( files_updated )

diagnostics_handler.BuffersModifiedByServer( file_list )

elif response is False:
# Don't keep polling for this file
return False
Expand Down
91 changes: 59 additions & 32 deletions python/ycm/diagnostic_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def UpdateWithNewDiagnostics( self, diags, open_on_edit = False ):


def RefreshDiagnosticsUI( self, open_on_edit = False ):
if self._user_options[ 'echo_all_diagnostics' ]:
self._EchoAllDiagnostics()
if self._user_options[ 'echo_current_diagnostic' ]:
self._EchoDiagnostic()

Expand All @@ -89,6 +91,12 @@ def RefreshDiagnosticsUI( self, open_on_edit = False ):


def ClearDiagnosticsUI( self ):
if self._user_options[ 'echo_all_diagnostics' ]:
tp.ClearTextProperties( self._bufnr,
prop_types = [ 'YcmVirtDiagPadding',
'YcmVirtDiagError',
'YcmVirtDiagWarning' ] )

if self._user_options[ 'echo_current_diagnostic' ]:
self._ClearCurrentDiagnostic()

Expand Down Expand Up @@ -133,8 +141,9 @@ def _ClearCurrentDiagnostic( self, will_be_replaced=False ):
if not self._diag_message_needs_clearing:
return

if ( not vimsupport.VimIsNeovim() and
self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text' ):
if ( not vimsupport.VimIsNeovim()
and self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text'
and not self._user_options[ 'echo_all_diagnostics' ] ):
tp.ClearTextProperties( self._bufnr,
prop_types = [ 'YcmVirtDiagPadding',
'YcmVirtDiagError',
Expand All @@ -146,15 +155,9 @@ def _ClearCurrentDiagnostic( self, will_be_replaced=False ):
self._diag_message_needs_clearing = False


def _EchoDiagnosticText( self, line_num, first_diag, text ):
self._ClearCurrentDiagnostic( bool( text ) )

if ( not vimsupport.VimIsNeovim() and
self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text' ):
if not text:
return

def MakeVritualTextProperty( prop_type, text, position='after' ):
def _PlaceDiagnosticVirtualText( self, line_num, first_diag, text ):
def MakeVritualTextProperty( prop_type, text, position='after' ):
try:
vimsupport.AddTextProperty( self._bufnr,
line_num,
0,
Expand All @@ -164,24 +167,51 @@ def MakeVritualTextProperty( prop_type, text, position='after' ):
'text_align': position,
'text_wrap': 'wrap'
} )
except vim.error:
pass

if vim.options[ 'ambiwidth' ] != 'double':
marker = '⚠'
else:
marker = '>'

MakeVritualTextProperty(
'YcmVirtDiagPadding',
' ' * vim.buffers[ self._bufnr ].options[ 'shiftwidth' ] ),
MakeVritualTextProperty(
'YcmVirtDiagError' if _DiagnosticIsError( first_diag )
else 'YcmVirtDiagWarning',
marker + ' ' + [ line for line in text.splitlines() if line ][ 0 ] )
if vim.options[ 'ambiwidth' ] != 'double':
marker = '⚠'
else:
if not text:
# We already cleared it
return
marker = '>'

MakeVritualTextProperty(
'YcmVirtDiagPadding',
' ' * vim.buffers[ self._bufnr ].options[ 'shiftwidth' ] ),
MakeVritualTextProperty(
'YcmVirtDiagError' if _DiagnosticIsError( first_diag )
else 'YcmVirtDiagWarning',
marker + ' ' + [ line for line in text.splitlines() if line ][ 0 ] )


def _EchoAllDiagnostics( self ):
if vimsupport.VimIsNeovim():
return

tp.ClearTextProperties( self._bufnr,
prop_types = [ 'YcmVirtDiagPadding',
'YcmVirtDiagError',
'YcmVirtDiagWarning' ] )

for line, diags in self._line_to_diags.items():
if not diags:
continue
num_diags = f' [+{ len( diags ) - 1 }]' if len( diags ) > 1 else ''
diag = diags[ 0 ]
self._PlaceDiagnosticVirtualText( line, diag, diag[ 'text' ] + num_diags )


def _EchoDiagnosticText( self, line_num, first_diag, text ):
self._ClearCurrentDiagnostic( bool( text ) )

if not text:
return

if ( not vimsupport.VimIsNeovim()
and self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text'
and not self._user_options[ 'echo_all_diagnostics' ] ):
self._PlaceDiagnosticVirtualText( line_num, first_diag, text )
else:
vimsupport.PostVimMessage( text, warning = False, truncate = True )

self._diag_message_needs_clearing = True
Expand Down Expand Up @@ -279,16 +309,13 @@ def _ConvertDiagListToDict( self ):
for diag in self._diagnostics:
location_extent = diag[ 'location_extent' ]
start = location_extent[ 'start' ]
end = location_extent[ 'end' ]
bufnr = vimsupport.GetBufferNumberForFilename( start[ 'filepath' ] )
if bufnr == self._bufnr:
for line_number in range( start[ 'line_num' ], end[ 'line_num' ] + 1 ):
self._line_to_diags[ line_number ].append( diag )
self._line_to_diags[ start[ 'line_num' ] ].append( diag )

for diags in self._line_to_diags.values():
# We also want errors to be listed before warnings so that errors aren't
# hidden by the warnings; Vim won't place a sign over an existing one.
diags.sort( key = lambda diag: ( diag[ 'kind' ],
diags.sort( key = lambda diag: ( diag.get( 'severity', 0 ),
diag[ 'kind' ],
diag[ 'location' ][ 'column_num' ] ) )


Expand Down
Loading
Loading