ycm_core now imported after extra conf preload
This commit is contained in:
parent
bc607724f0
commit
b903867cdd
210
python/ycm/server/handlers.py
Normal file
210
python/ycm/server/handlers.py
Normal file
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
|
||||
#
|
||||
# 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 atexit
|
||||
import logging
|
||||
import json
|
||||
import bottle
|
||||
import httplib
|
||||
from bottle import request, response
|
||||
import server_state
|
||||
from ycm import user_options_store
|
||||
from ycm.server.responses import BuildExceptionResponse
|
||||
from ycm import extra_conf_store
|
||||
|
||||
# num bytes for the request body buffer; request.json only works if the request
|
||||
# size is less than this
|
||||
bottle.Request.MEMFILE_MAX = 300 * 1024
|
||||
|
||||
# TODO: rename these to _lower_case
|
||||
SERVER_STATE = None
|
||||
LOGGER = logging.getLogger( __name__ )
|
||||
app = bottle.Bottle()
|
||||
|
||||
|
||||
@app.post( '/event_notification' )
|
||||
def EventNotification():
|
||||
LOGGER.info( 'Received event notification' )
|
||||
request_data = request.json
|
||||
event_name = request_data[ 'event_name' ]
|
||||
LOGGER.debug( 'Event name: %s', event_name )
|
||||
|
||||
event_handler = 'On' + event_name
|
||||
getattr( SERVER_STATE.GetGeneralCompleter(), event_handler )( request_data )
|
||||
|
||||
filetypes = request_data[ 'filetypes' ]
|
||||
response_data = None
|
||||
if SERVER_STATE.FiletypeCompletionUsable( filetypes ):
|
||||
response_data = getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ),
|
||||
event_handler )( request_data )
|
||||
|
||||
if response_data:
|
||||
return _JsonResponse( response_data )
|
||||
|
||||
|
||||
@app.post( '/run_completer_command' )
|
||||
def RunCompleterCommand():
|
||||
LOGGER.info( 'Received command request' )
|
||||
request_data = request.json
|
||||
completer = _GetCompleterForRequestData( request_data )
|
||||
|
||||
return _JsonResponse( completer.OnUserCommand(
|
||||
request_data[ 'command_arguments' ],
|
||||
request_data ) )
|
||||
|
||||
|
||||
@app.post( '/completions' )
|
||||
def GetCompletions():
|
||||
LOGGER.info( 'Received completion request' )
|
||||
request_data = request.json
|
||||
do_filetype_completion = SERVER_STATE.ShouldUseFiletypeCompleter(
|
||||
request_data )
|
||||
LOGGER.debug( 'Using filetype completion: %s', do_filetype_completion )
|
||||
filetypes = request_data[ 'filetypes' ]
|
||||
completer = ( SERVER_STATE.GetFiletypeCompleter( filetypes ) if
|
||||
do_filetype_completion else
|
||||
SERVER_STATE.GetGeneralCompleter() )
|
||||
|
||||
return _JsonResponse( completer.ComputeCandidates( request_data ) )
|
||||
|
||||
|
||||
@app.get( '/user_options' )
|
||||
def GetUserOptions():
|
||||
LOGGER.info( 'Received user options GET request' )
|
||||
return _JsonResponse( dict( SERVER_STATE.user_options ) )
|
||||
|
||||
|
||||
@app.get( '/healthy' )
|
||||
def GetHealthy():
|
||||
LOGGER.info( 'Received health request' )
|
||||
return _JsonResponse( True )
|
||||
|
||||
|
||||
@app.post( '/user_options' )
|
||||
def SetUserOptions():
|
||||
LOGGER.info( 'Received user options POST request' )
|
||||
UpdateUserOptions( request.json )
|
||||
|
||||
|
||||
@app.post( '/semantic_completion_available' )
|
||||
def FiletypeCompletionAvailable():
|
||||
LOGGER.info( 'Received filetype completion available request' )
|
||||
return _JsonResponse( SERVER_STATE.FiletypeCompletionAvailable(
|
||||
request.json[ 'filetypes' ] ) )
|
||||
|
||||
|
||||
@app.post( '/defined_subcommands' )
|
||||
def DefinedSubcommands():
|
||||
LOGGER.info( 'Received defined subcommands request' )
|
||||
completer = _GetCompleterForRequestData( request.json )
|
||||
|
||||
return _JsonResponse( completer.DefinedSubcommands() )
|
||||
|
||||
|
||||
@app.post( '/detailed_diagnostic' )
|
||||
def GetDetailedDiagnostic():
|
||||
LOGGER.info( 'Received detailed diagnostic request' )
|
||||
request_data = request.json
|
||||
completer = _GetCompleterForRequestData( request_data )
|
||||
|
||||
return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) )
|
||||
|
||||
|
||||
@app.post( '/load_extra_conf_file' )
|
||||
def LoadExtraConfFile():
|
||||
LOGGER.info( 'Received extra conf load request' )
|
||||
request_data = request.json
|
||||
extra_conf_store.Load( request_data[ 'filepath' ], force = True )
|
||||
|
||||
|
||||
@app.post( '/debug_info' )
|
||||
def DebugInfo():
|
||||
# This can't be at the top level because of possible extra conf preload
|
||||
import ycm_core
|
||||
LOGGER.info( 'Received debug info request' )
|
||||
|
||||
output = []
|
||||
has_clang_support = ycm_core.HasClangSupport()
|
||||
output.append( 'Server has Clang support compiled in: {0}'.format(
|
||||
has_clang_support ) )
|
||||
|
||||
if has_clang_support:
|
||||
output.append( 'Clang version: ' + ycm_core.ClangVersion() )
|
||||
|
||||
request_data = request.json
|
||||
try:
|
||||
output.append(
|
||||
_GetCompleterForRequestData( request_data ).DebugInfo( request_data) )
|
||||
except:
|
||||
pass
|
||||
return _JsonResponse( '\n'.join( output ) )
|
||||
|
||||
|
||||
# The type of the param is Bottle.HTTPError
|
||||
@app.error( httplib.INTERNAL_SERVER_ERROR )
|
||||
def ErrorHandler( httperror ):
|
||||
return _JsonResponse( BuildExceptionResponse( httperror.exception,
|
||||
httperror.traceback ) )
|
||||
|
||||
|
||||
def _JsonResponse( data ):
|
||||
response.set_header( 'Content-Type', 'application/json' )
|
||||
return json.dumps( data, default = _UniversalSerialize )
|
||||
|
||||
|
||||
def _UniversalSerialize( obj ):
|
||||
serialized = obj.__dict__.copy()
|
||||
serialized[ 'TYPE' ] = type( obj ).__name__
|
||||
return serialized
|
||||
|
||||
|
||||
def _GetCompleterForRequestData( request_data ):
|
||||
completer_target = request_data.get( 'completer_target', None )
|
||||
|
||||
if completer_target == 'identifier':
|
||||
return SERVER_STATE.GetGeneralCompleter().GetIdentifierCompleter()
|
||||
elif completer_target == 'filetype_default' or not completer_target:
|
||||
return SERVER_STATE.GetFiletypeCompleter( request_data[ 'filetypes' ] )
|
||||
else:
|
||||
return SERVER_STATE.GetFiletypeCompleter( [ completer_target ] )
|
||||
|
||||
|
||||
@atexit.register
|
||||
def _ServerShutdown():
|
||||
if SERVER_STATE:
|
||||
SERVER_STATE.Shutdown()
|
||||
extra_conf_store.Shutdown()
|
||||
|
||||
|
||||
def UpdateUserOptions( options ):
|
||||
global SERVER_STATE
|
||||
|
||||
if not options:
|
||||
return
|
||||
|
||||
user_options_store.SetAll( options )
|
||||
SERVER_STATE = server_state.ServerState( options )
|
||||
|
||||
|
||||
def SetServerStateToDefaults():
|
||||
global SERVER_STATE, LOGGER
|
||||
LOGGER = logging.getLogger( __name__ )
|
||||
user_options_store.LoadDefaults()
|
||||
SERVER_STATE = server_state.ServerState( user_options_store.GetAll() )
|
||||
extra_conf_store.Reset()
|
@ -19,7 +19,6 @@
|
||||
|
||||
import imp
|
||||
import os
|
||||
from ycm import extra_conf_store
|
||||
from ycm.utils import ForceSemanticCompletion
|
||||
from ycm.completers.general.general_completer_store import GeneralCompleterStore
|
||||
from ycm.completers.completer_utils import PathToFiletypeCompleterPluginLoader
|
||||
@ -30,7 +29,6 @@ class ServerState( object ):
|
||||
self._user_options = user_options
|
||||
self._filetype_completers = {}
|
||||
self._gencomp = GeneralCompleterStore( self._user_options )
|
||||
extra_conf_store.CallGlobalExtraConfYcmCorePreloadIfExists()
|
||||
|
||||
|
||||
@property
|
||||
@ -44,7 +42,6 @@ class ServerState( object ):
|
||||
completer.Shutdown()
|
||||
|
||||
self._gencomp.Shutdown()
|
||||
extra_conf_store.Shutdown()
|
||||
|
||||
|
||||
def _GetFiletypeCompleterForFiletype( self, filetype ):
|
||||
|
34
python/ycm/server/server_utils.py
Normal file
34
python/ycm/server/server_utils.py
Normal file
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
|
||||
#
|
||||
# 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 sys
|
||||
import os
|
||||
|
||||
def SetUpPythonPath():
|
||||
# We want to have the YouCompleteMe/python directory on the Python PATH
|
||||
# because all the code already assumes that it's there. This is a relic from
|
||||
# before the client/server architecture.
|
||||
# TODO: Fix things so that this is not needed anymore when we split ycmd into
|
||||
# a separate repository.
|
||||
sys.path.insert( 0, os.path.join(
|
||||
os.path.dirname( os.path.abspath( __file__ ) ),
|
||||
'../..' ) )
|
||||
|
||||
from ycm import utils
|
||||
utils.AddThirdPartyFoldersToSysPath()
|
@ -20,8 +20,10 @@
|
||||
import os
|
||||
import httplib
|
||||
import time
|
||||
from ..server_utils import SetUpPythonPath
|
||||
SetUpPythonPath()
|
||||
from webtest import TestApp
|
||||
from .. import ycmd
|
||||
from .. import handlers
|
||||
from ..responses import BuildCompletionData, UnknownExtraConf
|
||||
from nose.tools import ok_, eq_, with_setup
|
||||
from hamcrest import ( assert_that, has_items, has_entry, contains,
|
||||
@ -73,7 +75,7 @@ def CompletionEntryMatcher( insertion_text ):
|
||||
|
||||
|
||||
def Setup():
|
||||
ycmd.SetServerStateToDefaults()
|
||||
handlers.SetServerStateToDefaults()
|
||||
|
||||
|
||||
def PathToTestDataDir():
|
||||
@ -87,7 +89,7 @@ def PathToTestFile( test_basename ):
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_IdentifierCompleter_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
event_data = BuildRequest( contents = 'foo foogoo ba',
|
||||
event_name = 'FileReadyToParse' )
|
||||
|
||||
@ -104,7 +106,7 @@ def GetCompletions_IdentifierCompleter_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_CsCompleter_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
filepath = PathToTestFile( 'testy/Program.cs' )
|
||||
contents = open( filepath ).read()
|
||||
event_data = BuildRequest( filepath = filepath,
|
||||
@ -138,7 +140,7 @@ def GetCompletions_CsCompleter_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ClangCompleter_WorksWithExplicitFlags_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
struct Foo {
|
||||
int x;
|
||||
@ -170,7 +172,7 @@ int main()
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ClangCompleter_UnknownExtraConfException_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
filepath = PathToTestFile( 'basic.cpp' )
|
||||
completion_data = BuildRequest( filepath = filepath,
|
||||
filetype = 'cpp',
|
||||
@ -189,7 +191,7 @@ def GetCompletions_ClangCompleter_UnknownExtraConfException_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ClangCompleter_WorksWhenExtraConfExplicitlyAllowed_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
app.post_json( '/load_extra_conf_file',
|
||||
{ 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } )
|
||||
|
||||
@ -209,7 +211,7 @@ def GetCompletions_ClangCompleter_WorksWhenExtraConfExplicitlyAllowed_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ClangCompleter_ForceSemantic_OnlyFileteredCompletions_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
int main()
|
||||
{
|
||||
@ -241,7 +243,7 @@ int main()
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ForceSemantic_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
|
||||
completion_data = BuildRequest( filetype = 'python',
|
||||
force_semantic = True )
|
||||
@ -254,7 +256,7 @@ def GetCompletions_ForceSemantic_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
event_data = BuildRequest( event_name = 'FileReadyToParse',
|
||||
syntax_keywords = ['foo', 'bar', 'zoo'] )
|
||||
|
||||
@ -271,7 +273,7 @@ def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_UltiSnipsCompleter_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
event_data = BuildRequest(
|
||||
event_name = 'BufferVisit',
|
||||
ultisnips_snippets = [
|
||||
@ -292,7 +294,7 @@ def GetCompletions_UltiSnipsCompleter_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def RunCompleterCommand_GoTo_Jedi_ZeroBasedLineAndColumn_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
def foo():
|
||||
pass
|
||||
@ -318,7 +320,7 @@ foo()
|
||||
|
||||
@with_setup( Setup )
|
||||
def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
struct Foo {
|
||||
int x;
|
||||
@ -352,7 +354,7 @@ int main()
|
||||
|
||||
@with_setup( Setup )
|
||||
def DefinedSubcommands_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
subcommands_data = BuildRequest( completer_target = 'python' )
|
||||
|
||||
eq_( [ 'GoToDefinition',
|
||||
@ -363,7 +365,7 @@ def DefinedSubcommands_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
subcommands_data = BuildRequest( filetype = 'python' )
|
||||
|
||||
eq_( [ 'GoToDefinition',
|
||||
@ -374,7 +376,7 @@ def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def Diagnostics_ClangCompleter_ZeroBasedLineAndColumn_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
struct Foo {
|
||||
int x // semicolon missing here!
|
||||
@ -399,7 +401,7 @@ struct Foo {
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetDetailedDiagnostic_ClangCompleter_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
contents = """
|
||||
struct Foo {
|
||||
int x // semicolon missing here!
|
||||
@ -427,7 +429,7 @@ struct Foo {
|
||||
|
||||
@with_setup( Setup )
|
||||
def FiletypeCompletionAvailable_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
request_data = {
|
||||
'filetypes': ['python']
|
||||
}
|
||||
@ -438,7 +440,7 @@ def FiletypeCompletionAvailable_Works_test():
|
||||
|
||||
@with_setup( Setup )
|
||||
def UserOptions_Works_test():
|
||||
app = TestApp( ycmd.app )
|
||||
app = TestApp( handlers.app )
|
||||
options = app.get( '/user_options' ).json
|
||||
ok_( len( options ) )
|
||||
|
||||
|
@ -17,214 +17,24 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from server_utils import SetUpPythonPath
|
||||
SetUpPythonPath()
|
||||
|
||||
import sys
|
||||
import os
|
||||
import atexit
|
||||
|
||||
# We want to have the YouCompleteMe/python directory on the Python PATH because
|
||||
# all the code already assumes that it's there. This is a relic from before the
|
||||
# client/server architecture.
|
||||
# TODO: Fix things so that this is not needed anymore when we split ycmd into a
|
||||
# separate repository.
|
||||
sys.path.insert( 0, os.path.join(
|
||||
os.path.dirname( os.path.abspath( __file__ ) ),
|
||||
'../..' ) )
|
||||
|
||||
from ycm import utils
|
||||
utils.AddThirdPartyFoldersToSysPath()
|
||||
|
||||
import logging
|
||||
import json
|
||||
import bottle
|
||||
import argparse
|
||||
import httplib
|
||||
import waitress
|
||||
from bottle import request, response
|
||||
import server_state
|
||||
from ycm import user_options_store
|
||||
from ycm.server.responses import BuildExceptionResponse
|
||||
from ycm import extra_conf_store
|
||||
|
||||
# num bytes for the request body buffer; request.json only works if the request
|
||||
# size is less than this
|
||||
bottle.Request.MEMFILE_MAX = 300 * 1024
|
||||
|
||||
# TODO: rename these to _lower_case
|
||||
SERVER_STATE = None
|
||||
LOGGER = None
|
||||
app = bottle.Bottle()
|
||||
|
||||
|
||||
@app.post( '/event_notification' )
|
||||
def EventNotification():
|
||||
LOGGER.info( 'Received event notification' )
|
||||
request_data = request.json
|
||||
event_name = request_data[ 'event_name' ]
|
||||
LOGGER.debug( 'Event name: %s', event_name )
|
||||
|
||||
event_handler = 'On' + event_name
|
||||
getattr( SERVER_STATE.GetGeneralCompleter(), event_handler )( request_data )
|
||||
|
||||
filetypes = request_data[ 'filetypes' ]
|
||||
response_data = None
|
||||
if SERVER_STATE.FiletypeCompletionUsable( filetypes ):
|
||||
response_data = getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ),
|
||||
event_handler )( request_data )
|
||||
|
||||
if response_data:
|
||||
return _JsonResponse( response_data )
|
||||
|
||||
|
||||
@app.post( '/run_completer_command' )
|
||||
def RunCompleterCommand():
|
||||
LOGGER.info( 'Received command request' )
|
||||
request_data = request.json
|
||||
completer = _GetCompleterForRequestData( request_data )
|
||||
|
||||
return _JsonResponse( completer.OnUserCommand(
|
||||
request_data[ 'command_arguments' ],
|
||||
request_data ) )
|
||||
|
||||
|
||||
@app.post( '/completions' )
|
||||
def GetCompletions():
|
||||
LOGGER.info( 'Received completion request' )
|
||||
request_data = request.json
|
||||
do_filetype_completion = SERVER_STATE.ShouldUseFiletypeCompleter(
|
||||
request_data )
|
||||
LOGGER.debug( 'Using filetype completion: %s', do_filetype_completion )
|
||||
filetypes = request_data[ 'filetypes' ]
|
||||
completer = ( SERVER_STATE.GetFiletypeCompleter( filetypes ) if
|
||||
do_filetype_completion else
|
||||
SERVER_STATE.GetGeneralCompleter() )
|
||||
|
||||
return _JsonResponse( completer.ComputeCandidates( request_data ) )
|
||||
|
||||
|
||||
@app.get( '/user_options' )
|
||||
def GetUserOptions():
|
||||
LOGGER.info( 'Received user options GET request' )
|
||||
return _JsonResponse( dict( SERVER_STATE.user_options ) )
|
||||
|
||||
|
||||
@app.get( '/healthy' )
|
||||
def GetHealthy():
|
||||
LOGGER.info( 'Received health request' )
|
||||
return _JsonResponse( True )
|
||||
|
||||
|
||||
@app.post( '/user_options' )
|
||||
def SetUserOptions():
|
||||
LOGGER.info( 'Received user options POST request' )
|
||||
_SetUserOptions( request.json )
|
||||
|
||||
|
||||
@app.post( '/semantic_completion_available' )
|
||||
def FiletypeCompletionAvailable():
|
||||
LOGGER.info( 'Received filetype completion available request' )
|
||||
return _JsonResponse( SERVER_STATE.FiletypeCompletionAvailable(
|
||||
request.json[ 'filetypes' ] ) )
|
||||
|
||||
|
||||
@app.post( '/defined_subcommands' )
|
||||
def DefinedSubcommands():
|
||||
LOGGER.info( 'Received defined subcommands request' )
|
||||
completer = _GetCompleterForRequestData( request.json )
|
||||
|
||||
return _JsonResponse( completer.DefinedSubcommands() )
|
||||
|
||||
|
||||
@app.post( '/detailed_diagnostic' )
|
||||
def GetDetailedDiagnostic():
|
||||
LOGGER.info( 'Received detailed diagnostic request' )
|
||||
request_data = request.json
|
||||
completer = _GetCompleterForRequestData( request_data )
|
||||
|
||||
return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) )
|
||||
|
||||
|
||||
@app.post( '/load_extra_conf_file' )
|
||||
def LoadExtraConfFile():
|
||||
LOGGER.info( 'Received extra conf load request' )
|
||||
request_data = request.json
|
||||
extra_conf_store.Load( request_data[ 'filepath' ], force = True )
|
||||
|
||||
|
||||
@app.post( '/debug_info' )
|
||||
def DebugInfo():
|
||||
# This can't be at the top level because of possible extra conf preload
|
||||
import ycm_core
|
||||
LOGGER.info( 'Received debug info request' )
|
||||
|
||||
output = []
|
||||
has_clang_support = ycm_core.HasClangSupport()
|
||||
output.append( 'Server has Clang support compiled in: {0}'.format(
|
||||
has_clang_support ) )
|
||||
|
||||
if has_clang_support:
|
||||
output.append( 'Clang version: ' + ycm_core.ClangVersion() )
|
||||
|
||||
request_data = request.json
|
||||
try:
|
||||
output.append(
|
||||
_GetCompleterForRequestData( request_data ).DebugInfo( request_data) )
|
||||
except:
|
||||
pass
|
||||
return _JsonResponse( '\n'.join( output ) )
|
||||
|
||||
|
||||
# The type of the param is Bottle.HTTPError
|
||||
@app.error( httplib.INTERNAL_SERVER_ERROR )
|
||||
def ErrorHandler( httperror ):
|
||||
return _JsonResponse( BuildExceptionResponse( httperror.exception,
|
||||
httperror.traceback ) )
|
||||
|
||||
|
||||
def _JsonResponse( data ):
|
||||
response.set_header( 'Content-Type', 'application/json' )
|
||||
return json.dumps( data, default = _UniversalSerialize )
|
||||
|
||||
|
||||
def _UniversalSerialize( obj ):
|
||||
serialized = obj.__dict__.copy()
|
||||
serialized[ 'TYPE' ] = type( obj ).__name__
|
||||
return serialized
|
||||
|
||||
|
||||
def _GetCompleterForRequestData( request_data ):
|
||||
completer_target = request_data.get( 'completer_target', None )
|
||||
|
||||
if completer_target == 'identifier':
|
||||
return SERVER_STATE.GetGeneralCompleter().GetIdentifierCompleter()
|
||||
elif completer_target == 'filetype_default' or not completer_target:
|
||||
return SERVER_STATE.GetFiletypeCompleter( request_data[ 'filetypes' ] )
|
||||
else:
|
||||
return SERVER_STATE.GetFiletypeCompleter( [ completer_target ] )
|
||||
|
||||
|
||||
@atexit.register
|
||||
def _ServerShutdown():
|
||||
if SERVER_STATE:
|
||||
SERVER_STATE.Shutdown()
|
||||
|
||||
|
||||
def _SetUserOptions( options ):
|
||||
global SERVER_STATE
|
||||
|
||||
user_options_store.SetAll( options )
|
||||
SERVER_STATE = server_state.ServerState( options )
|
||||
|
||||
|
||||
def SetServerStateToDefaults():
|
||||
global SERVER_STATE, LOGGER
|
||||
LOGGER = logging.getLogger( __name__ )
|
||||
user_options_store.LoadDefaults()
|
||||
SERVER_STATE = server_state.ServerState( user_options_store.GetAll() )
|
||||
extra_conf_store.Reset()
|
||||
def YcmCoreSanityCheck():
|
||||
if 'ycm_core' in sys.modules:
|
||||
raise RuntimeError( 'ycm_core already imported, ycmd has a bug!' )
|
||||
|
||||
|
||||
def Main():
|
||||
global LOGGER
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument( '--host', type = str, default = 'localhost',
|
||||
help = 'server hostname')
|
||||
@ -237,18 +47,31 @@ def Main():
|
||||
help = 'file with user options, in JSON format' )
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.options_file:
|
||||
_SetUserOptions( json.load( open( args.options_file, 'r' ) ) )
|
||||
|
||||
numeric_level = getattr( logging, args.log.upper(), None )
|
||||
if not isinstance( numeric_level, int ):
|
||||
raise ValueError( 'Invalid log level: %s' % args.log )
|
||||
|
||||
# Has to be called before any call to logging.getLogger()
|
||||
logging.basicConfig( format = '%(asctime)s - %(levelname)s - %(message)s',
|
||||
level = numeric_level )
|
||||
|
||||
LOGGER = logging.getLogger( __name__ )
|
||||
waitress.serve( app, host = args.host, port = args.port, threads = 10 )
|
||||
options = None
|
||||
if args.options_file:
|
||||
options = json.load( open( args.options_file, 'r' ) )
|
||||
user_options_store.SetAll( options )
|
||||
# This ensures that ycm_core is not loaded before extra conf preload
|
||||
# was run.
|
||||
YcmCoreSanityCheck()
|
||||
extra_conf_store.CallGlobalExtraConfYcmCorePreloadIfExists()
|
||||
|
||||
# This can't be a top-level import because it transitively imports ycm_core
|
||||
# which we want to be imported ONLY after extra conf preload has executed.
|
||||
import handlers
|
||||
handlers.UpdateUserOptions( options )
|
||||
waitress.serve( handlers.app,
|
||||
host = args.host,
|
||||
port = args.port,
|
||||
threads = 10 )
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user