Commit 00af0381 authored by Onur Aslan's avatar Onur Aslan

Imported Upstream version 0+20151025+gitf20c693

parent d81fc097
......@@ -32,7 +32,7 @@ You should also **search the archives of the [ycm-users][] mailing list**.
Lastly, **make sure you are running the latest version of YCM**. The issue you
have encountered may have already been fixed. **Don't forget to recompile
ycm_core.so too** (usually by just running `install.sh` again).
ycm_core.so too** (usually by just running `install.py` again).
OK, so we've reached this far. You need to create an issue. First realize that
the time it takes to fix your issue is a multiple of how long it takes the
......
This diff is collapsed.
version: '{build}'
environment:
matrix:
- arch: 32
- arch: 64
install:
- git submodule update --init --recursive
- ps: $env:python = if ($env:arch -eq 32) { 'C:\Python27' } else { 'C:\Python27-x64' }
- ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:\get-pip.py')
- set PATH=%python%;%python%\Scripts;%PATH%
- python C:\get-pip.py
- pip install -r python\test_requirements.txt
build_script:
- run_tests.py
# Disable automatic tests
test: off
......@@ -51,6 +51,7 @@ function! youcompleteme#Enable()
return
endif
call s:SetUpCommands()
call s:SetUpCpoptions()
call s:SetUpCompleteopt()
call s:SetUpKeyMappings()
......@@ -84,6 +85,7 @@ function! youcompleteme#Enable()
autocmd InsertLeave * call s:OnInsertLeave()
autocmd InsertEnter * call s:OnInsertEnter()
autocmd VimLeave * call s:OnVimLeave()
autocmd CompleteDone * call s:OnCompleteDone()
augroup END
" Calling these once solves the problem of BufReadPre/BufRead/BufEnter not
......@@ -129,20 +131,19 @@ from ycm import base
base.LoadJsonDefaultsIntoVim()
from ycmd import user_options_store
user_options_store.SetAll( base.BuildServerConf() )
from ycm import vimsupport
from ycm import paths, vimsupport
popen_args = [ utils.PathToPythonInterpreter(),
os.path.join( script_folder,
'../third_party/ycmd/check_core_version.py') ]
popen_args = [ paths.PathToPythonInterpreter(),
paths.PathToCheckCoreVersion() ]
if utils.SafePopen( popen_args ).wait() == 2:
vimsupport.PostVimMessage(
'YouCompleteMe unavailable: YCM support libs too old, PLEASE RECOMPILE' )
vim.command( 'return 0')
vim.command( 'return 0' )
from ycm.youcompleteme import YouCompleteMe
ycm_state = YouCompleteMe( user_options_store.GetAll() )
vim.command( 'return 1')
vim.command( 'return 1' )
EOF
endfunction
......@@ -305,6 +306,17 @@ function! s:AllowedToCompleteInCurrentFile()
endfunction
function! s:SetUpCommands()
command! YcmRestartServer call s:RestartServer()
command! YcmShowDetailedDiagnostic call s:ShowDetailedDiagnostic()
command! YcmDebugInfo call s:DebugInfo()
command! -nargs=* -complete=custom,youcompleteme#SubCommandsComplete
\ YcmCompleter call s:CompleterCommand(<f-args>)
command! YcmForceCompileAndDiagnostics call s:ForceCompileAndDiagnostics()
command! YcmDiags call s:ShowDiagnostics()
endfunction
function! s:SetUpCpoptions()
" Without this flag in cpoptions, critical YCM mappings do not work. There's
" no way to not have this and have YCM working, so force the flag.
......@@ -359,6 +371,11 @@ function! s:OnVimLeave()
endfunction
function! s:OnCompleteDone()
py ycm_state.OnCompleteDone()
endfunction
function! s:OnBufferReadPre(filename)
let threshold = g:ycm_disable_for_files_larger_than_kb * 1024
......@@ -731,15 +748,11 @@ function! s:RestartServer()
py ycm_state.RestartServer()
endfunction
command! YcmRestartServer call s:RestartServer()
function! s:ShowDetailedDiagnostic()
py ycm_state.ShowDetailedDiagnostic()
endfunction
command! YcmShowDetailedDiagnostic call s:ShowDetailedDiagnostic()
function! s:DebugInfo()
echom "Printing YouCompleteMe debug information..."
......@@ -749,8 +762,6 @@ function! s:DebugInfo()
endfor
endfunction
command! YcmDebugInfo call s:DebugInfo()
function! s:CompleterCommand(...)
" CompleterCommand will call the OnUserCommand function of a completer.
......@@ -785,9 +796,6 @@ function! youcompleteme#OpenGoToList()
endfunction
command! -nargs=* -complete=custom,youcompleteme#SubCommandsComplete
\ YcmCompleter call s:CompleterCommand(<f-args>)
function! youcompleteme#SubCommandsComplete( arglead, cmdline, cursorpos )
return join( pyeval( 'ycm_state.GetDefinedSubcommands()' ),
\ "\n")
......@@ -826,8 +834,6 @@ function! s:ForceCompileAndDiagnostics()
echom "Diagnostics refreshed."
endfunction
command! YcmForceCompileAndDiagnostics call s:ForceCompileAndDiagnostics()
function! s:ShowDiagnostics()
let compilation_succeeded = s:ForceCompile()
......@@ -848,8 +854,6 @@ function! s:ShowDiagnostics()
endif
endfunction
command! YcmDiags call s:ShowDiagnostics()
" This is basic vim plugin boilerplate
let &cpo = s:save_cpo
......
This diff is collapsed.
#!/usr/bin/env python
import os
import subprocess
import sys
import os.path as p
import glob
DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) )
DIR_OF_OLD_LIBS = p.join( DIR_OF_THIS_SCRIPT, 'python' )
def Main():
build_file = p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'ycmd', 'build.py' )
if not p.isfile( build_file ):
sys.exit( 'File ' + build_file + ' does not exist; you probably forgot '
'to run:\n\tgit submodule update --init --recursive\n\n' )
python_binary = sys.executable
subprocess.call( [ python_binary, build_file ] + sys.argv[1:] )
# Remove old YCM libs if present so that YCM can start.
old_libs = (
glob.glob( p.join( DIR_OF_OLD_LIBS, '*ycm_core.*' ) ) +
glob.glob( p.join( DIR_OF_OLD_LIBS, '*ycm_client_support.*' ) ) +
glob.glob( p.join( DIR_OF_OLD_LIBS, '*clang*.*') ) )
for lib in old_libs:
os.remove( lib )
if __name__ == "__main__":
Main()
#!/usr/bin/env bash
#!/bin/sh
set -e
echo "WARNING: this script is deprecated. Use the install.py script instead." 1>&2
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
build_file=$SCRIPT_DIR/third_party/ycmd/build.py
if [[ ! -f "$build_file" ]]; then
echo "File $build_file doesn't exist; you probably forgot to run:"
printf "\n\tgit submodule update --init --recursive\n\n"
exit 1
fi
SCRIPT_DIR=$(dirname $0 || exit $?)
command_exists() {
command -v "$1" >/dev/null 2>&1 ;
......@@ -21,9 +14,4 @@ if command_exists python2; then
PYTHON_BINARY=python2
fi
$PYTHON_BINARY "$build_file" "$@"
# Remove old YCM libs if present so that YCM can start.
rm -f python/*ycm_core.* &> /dev/null
rm -f python/*ycm_client_support.* &> /dev/null
rm -f python/*clang*.* &> /dev/null
$PYTHON_BINARY "$SCRIPT_DIR/install.py" "$@" || exit $?
......@@ -27,9 +27,9 @@ endfunction
if exists( "g:loaded_youcompleteme" )
call s:restore_cpo()
finish
elseif v:version < 703 || (v:version == 703 && !has('patch584'))
elseif v:version < 703 || (v:version == 703 && !has('patch598'))
echohl WarningMsg |
\ echomsg "YouCompleteMe unavailable: requires Vim 7.3.584+" |
\ echomsg "YouCompleteMe unavailable: requires Vim 7.3.598+" |
\ echohl None
call s:restore_cpo()
finish
......
......@@ -163,7 +163,7 @@ def JsonFromFuture( future ):
response = future.result()
_ValidateResponseObject( response )
if response.status_code == requests.codes.server_error:
_RaiseExceptionForData( response.json() )
raise MakeServerException( response.json() )
# We let Requests handle the other status types, we only handle the 500
# error code.
......@@ -218,10 +218,9 @@ def _CheckServerIsHealthyWithCache():
except:
return False
def _RaiseExceptionForData( data ):
def MakeServerException( data ):
if data[ 'exception' ][ 'TYPE' ] == UnknownExtraConf.__name__:
raise UnknownExtraConf( data[ 'exception' ][ 'extra_conf_file' ] )
return UnknownExtraConf( data[ 'exception' ][ 'extra_conf_file' ] )
raise ServerError( '{0}: {1}'.format( data[ 'exception' ][ 'TYPE' ],
data[ 'message' ] ) )
return ServerError( '{0}: {1}'.format( data[ 'exception' ][ 'TYPE' ],
data[ 'message' ] ) )
......@@ -22,6 +22,7 @@ from ycm.client.base_request import BaseRequest, BuildRequestData, ServerError
from ycm import vimsupport
from ycmd.utils import ToUtf8IfNeeded
def _EnsureBackwardsCompatibility( arguments ):
if arguments and arguments[ 0 ] == 'GoToDefinitionElseDeclaration':
arguments[ 0 ] = 'GoTo'
......@@ -49,7 +50,7 @@ class CommandRequest( BaseRequest ):
} )
try:
self._response = self.PostDataToHandler( request_data,
'run_completer_command' )
'run_completer_command' )
except ServerError as e:
vimsupport.PostMultiLineNotice( e )
......@@ -57,6 +58,7 @@ class CommandRequest( BaseRequest ):
def Response( self ):
return self._response
def RunPostCommandActionsIfNeeded( self ):
if not self.Done() or not self._response:
return
......@@ -67,6 +69,9 @@ class CommandRequest( BaseRequest ):
self._HandleFixitResponse()
elif 'message' in self._response:
self._HandleMessageResponse()
elif 'detailed_info' in self._response:
self._HandleDetailedInfoResponse()
def _HandleGotoResponse( self ):
if isinstance( self._response, list ):
......@@ -75,56 +80,31 @@ class CommandRequest( BaseRequest ):
vim.eval( 'youcompleteme#OpenGoToList()' )
else:
vimsupport.JumpToLocation( self._response[ 'filepath' ],
self._response[ 'line_num' ],
self._response[ 'column_num' ] )
self._response[ 'line_num' ],
self._response[ 'column_num' ] )
def _HandleFixitResponse( self ):
if not len( self._response[ 'fixits' ] ):
vimsupport.EchoText( "No fixits found for current line" )
else:
fixit = self._response[ 'fixits' ][ 0 ]
# We need to track the difference in length, but ensuring we apply fixes
# in ascending order of insertion point.
fixit[ 'chunks' ].sort( key = lambda chunk: (
str(chunk[ 'range' ][ 'start' ][ 'line_num' ])
+ ','
+ str(chunk[ 'range' ][ 'start' ][ 'column_num' ])
))
# Remember the line number we're processing. Negative line number means we
# haven't processed any lines yet (by nature of being not equal to any
# real line number).
last_line = -1
# Counter of changes applied, so the user has a mental picture of the
# undo history this change is creating.
num_fixed = 0
line_delta = 0
for chunk in fixit[ 'chunks' ]:
if chunk[ 'range' ][ 'start' ][ 'line_num' ] != last_line:
# If this chunk is on a different line than the previous chunk,
# then ignore previous deltas (as offsets won't have changed).
last_line = chunk[ 'range' ][ 'end' ][ 'line_num' ]
char_delta = 0
(new_line_delta, new_char_delta) = vimsupport.ReplaceChunk(
chunk[ 'range' ][ 'start' ],
chunk[ 'range' ][ 'end' ],
chunk[ 'replacement_text' ],
line_delta, char_delta )
line_delta += new_line_delta
char_delta += new_char_delta
num_fixed = num_fixed + 1
vimsupport.EchoTextVimWidth("FixIt applied "
+ str(num_fixed)
+ " changes")
chunks = self._response[ 'fixits' ][ 0 ][ 'chunks' ]
vimsupport.ReplaceChunksList( chunks )
vimsupport.EchoTextVimWidth( "FixIt applied "
+ str( len( chunks ) )
+ " changes" )
def _HandleMessageResponse( self ):
vimsupport.EchoText( self._response[ 'message' ] )
def _HandleDetailedInfoResponse( self ):
vimsupport.WriteToPreviewWindow( self._response[ 'detailed_info' ] )
def SendCommandRequest( arguments, completer ):
request = CommandRequest( arguments, completer )
# This is a blocking call.
......
......@@ -19,10 +19,12 @@
from ycmd.utils import ToUtf8IfNeeded
from ycm.client.base_request import ( BaseRequest, JsonFromFuture,
HandleServerException )
HandleServerException,
MakeServerException )
TIMEOUT_SECONDS = 0.5
class CompletionRequest( BaseRequest ):
def __init__( self, request_data ):
super( CompletionRequest, self ).__init__()
......@@ -39,24 +41,40 @@ class CompletionRequest( BaseRequest ):
return self._response_future.done()
def Response( self ):
def RawResponse( self ):
if not self._response_future:
return []
try:
return _ConvertCompletionResponseToVimDatas(
JsonFromFuture( self._response_future ) )
response = JsonFromFuture( self._response_future )
errors = response['errors'] if 'errors' in response else []
for e in errors:
HandleServerException( MakeServerException( e ) )
return JsonFromFuture( self._response_future )[ 'completions' ]
except Exception as e:
HandleServerException( e )
return []
def _ConvertCompletionDataToVimData( completion_data ):
def Response( self ):
return _ConvertCompletionDatasToVimDatas( self.RawResponse() )
def ConvertCompletionDataToVimData( completion_data ):
# see :h complete-items for a description of the dictionary fields
vim_data = {
'word' : ToUtf8IfNeeded( completion_data[ 'insertion_text' ] ),
'dup' : 1,
}
if ( 'extra_data' in completion_data and
'doc_string' in completion_data[ 'extra_data' ] ):
doc_string = ToUtf8IfNeeded(
completion_data[ 'extra_data' ][ 'doc_string' ] )
else:
doc_string = ""
if 'menu_text' in completion_data:
vim_data[ 'abbr' ] = ToUtf8IfNeeded( completion_data[ 'menu_text' ] )
if 'extra_menu_info' in completion_data:
......@@ -66,10 +84,14 @@ def _ConvertCompletionDataToVimData( completion_data ):
completion_data[ 'kind' ] )[ 0 ].lower()
if 'detailed_info' in completion_data:
vim_data[ 'info' ] = ToUtf8IfNeeded( completion_data[ 'detailed_info' ] )
if doc_string:
vim_data[ 'info' ] += '\n' + doc_string
elif doc_string:
vim_data[ 'info' ] = doc_string
return vim_data
def _ConvertCompletionResponseToVimDatas( response_data ):
return [ _ConvertCompletionDataToVimData( x )
for x in response_data[ 'completions' ] ]
def _ConvertCompletionDatasToVimDatas( response_data ):
return [ ConvertCompletionDataToVimData( x )
for x in response_data ]
#!/usr/bin/env python
#
# Copyright (C) 2015 YouCompleteMe Contributors
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
from nose.tools import eq_
from ycm.test_utils import MockVimModule
vim_mock = MockVimModule()
from .. import completion_request
class ConvertCompletionResponseToVimDatas_test:
""" This class tests the
completion_request._ConvertCompletionResponseToVimDatas method """
def _Check( self, completion_data, expected_vim_data ):
vim_data = completion_request.ConvertCompletionDataToVimData(
completion_data )
try:
eq_( expected_vim_data, vim_data )
except:
print "Expected:\n'{0}'\nwhen parsing:\n'{1}'\nBut found:\n'{2}'".format(
expected_vim_data,
completion_data,
vim_data )
raise
def All_Fields_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
'extra_data': {
'doc_string': 'DOC STRING',
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO\nDOC STRING',
'dup' : 1,
} )
def Just_Detailed_Info_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO',
'dup' : 1,
} )
def Just_Doc_String_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'extra_data': {
'doc_string': 'DOC STRING',
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DOC STRING',
'dup' : 1,
} )
def Extra_Info_No_Doc_String_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'extra_data': {
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'dup' : 1,
} )
def Extra_Info_No_Doc_String_With_Detailed_Info_test( self ):
self._Check( {
'insertion_text': 'INSERTION TEXT',
'menu_text': 'MENU TEXT',
'extra_menu_info': 'EXTRA MENU INFO',
'kind': 'K',
'detailed_info': 'DETAILED INFO',
'extra_data': {
},
}, {
'word': 'INSERTION TEXT',
'abbr': 'MENU TEXT',
'menu': 'EXTRA MENU INFO',
'kind': 'k',
'info': 'DETAILED INFO',
'dup' : 1,
} )
#!/usr/bin/env python
#
# Copyright (C) 2015 YouCompleteMe contributors.
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
import os
import vim
import functools
from ycmd import utils
DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) )
WIN_PYTHON27_PATH = 'C:\python27\python.exe'
WIN_PYTHON26_PATH = 'C:\python26\python.exe'
def Memoize( obj ):
cache = obj.cache = {}
@functools.wraps( obj )
def memoizer( *args, **kwargs ):
key = str( args ) + str( kwargs )
if key not in cache:
cache[ key ] = obj( *args, **kwargs )
return cache[ key ]
return memoizer
@Memoize
def PathToPythonInterpreter():
user_path_to_python = vim.eval( 'g:ycm_path_to_python_interpreter' )
if user_path_to_python:
return user_path_to_python
# We check for 'python2' before 'python' because some OS's (I'm looking at
# you Arch Linux) have made the... interesting decision to point
# /usr/bin/python to python3.
python_names = [ 'python2', 'python' ]
path_to_python = utils.PathToFirstExistingExecutable( python_names )
if path_to_python:
return path_to_python
# On Windows, Python may not be on the PATH at all, so we check some common
# install locations.
if utils.OnWindows():
if os.path.exists( WIN_PYTHON27_PATH ):
return WIN_PYTHON27_PATH
elif os.path.exists( WIN_PYTHON26_PATH ):
return WIN_PYTHON26_PATH
raise RuntimeError( 'Python 2.7/2.6 not installed!' )
def PathToServerScript():
return os.path.join( DIR_OF_CURRENT_SCRIPT, '..', '..', 'third_party',
'ycmd', 'ycmd' )
def PathToCheckCoreVersion():
return os.path.join( DIR_OF_CURRENT_SCRIPT, '..', '..', 'third_party',
'ycmd', 'check_core_version.py' )
......@@ -20,17 +20,44 @@
from mock import MagicMock
import sys
# One-and only instance of mocked Vim object. The first 'import vim' that is
# executed binds the vim module to the instance of MagicMock that is created,
# and subsquent assignments to sys.modules[ 'vim' ] don't retrospectively update
# them. The result is that while running the tests, we must assign only one
# instance of MagicMock to sys.modules[ 'vim' ] and always return it.
#
# More explanation is available:
# https://github.com/Valloric/YouCompleteMe/pull/1694
VIM_MOCK = MagicMock()
def MockVimModule():
"""The 'vim' module is something that is only present when running inside the
Vim Python interpreter, so we replace it with a MagicMock for tests. """
Vim Python interpreter, so we replace it with a MagicMock for tests. If you
need to add additional mocks to vim module functions, then use 'patch' from
mock module, to ensure that the state of the vim mock is returned before the
next test. That is:
from ycm.test_utils import MockVimModule
from mock import patch
# Do this once
MockVimModule()
@patch( 'vim.eval', return_value='test' )
@patch( 'vim.command', side_effect=ValueError )
def test( vim_command, vim_eval ):
# use vim.command via vim_command, e.g.:
vim_command.assert_has_calls( ... )
Failure to use this approach may lead to unexpected failures in other
tests."""
def VimEval( value ):
if value == "g:ycm_min_num_of_chars_for_completion":
return 0
return ''
vim_mock = MagicMock()
vim_mock.eval = MagicMock( side_effect = VimEval )
sys.modules[ 'vim' ] = vim_mock
return vim_mock
VIM_MOCK.eval = MagicMock( side_effect = VimEval )
sys.modules[ 'vim' ] = VIM_MOCK
return VIM_MOCK
This diff is collapsed.
......@@ -17,11 +17,12 @@
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
from ycm.test_utils import MockVimModule
MockVimModule()
import os
from nose.tools import eq_
from hamcrest import assert_that, has_items
from ycm.test_utils import MockVimModule
vim_mock = MockVimModule()
from ycm import syntax_parse
......
This diff is collapsed.
......@@ -21,6 +21,7 @@ import vim
import os
import tempfile
import json
import re
from ycmd.utils import ToUtf8IfNeeded
from ycmd import user_options_store
......@@ -60,14 +61,20 @@ def TextAfterCursor():
return vim.current.line[ CurrentColumn(): ]
def TextBeforeCursor():
"""Returns the text before CurrentColumn."""
return vim.current.line[ :CurrentColumn() ]
# Expects version_string in 'MAJOR.MINOR.PATCH' format, e.g. '7.4.301'
def VimVersionAtLeast( version_string ):
major, minor, patch = [ int( x )