YouCompleteMe/python/ycm/utils.py

188 lines
5.5 KiB
Python

#!/usr/bin/env python
#
# Copyright (C) 2011, 2012 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 tempfile
import os
import sys
import signal
import functools
import socket
import stat
from distutils.spawn import find_executable
import subprocess
WIN_PYTHON27_PATH = 'C:\python27\pythonw.exe'
WIN_PYTHON26_PATH = 'C:\python26\pythonw.exe'
def IsIdentifierChar( char ):
return char.isalnum() or char == '_'
def SanitizeQuery( query ):
return query.strip()
def ToUtf8IfNeeded( string_or_unicode ):
if isinstance( string_or_unicode, unicode ):
return string_or_unicode.encode( 'utf8' )
return string_or_unicode
def PathToTempDir():
tempdir = os.path.join( tempfile.gettempdir(), 'ycm_temp' )
if not os.path.exists( tempdir ):
os.makedirs( tempdir )
# Needed to support multiple users working on the same machine;
# see issue 606.
MakeFolderAccessibleToAll( tempdir )
return tempdir
def MakeFolderAccessibleToAll( path_to_folder ):
current_stat = os.stat( path_to_folder )
# readable, writable and executable by everyone
flags = ( current_stat.st_mode | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH
| stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP )
os.chmod( path_to_folder, flags )
def RunningInsideVim():
try:
import vim # NOQA
return True
except ImportError:
return False
def GetUnusedLocalhostPort():
sock = socket.socket()
# This tells the OS to give us any free port in the range [1024 - 65535]
sock.bind( ( '', 0 ) )
port = sock.getsockname()[ 1 ]
sock.close()
return port
def RemoveIfExists( filename ):
try:
os.remove( filename )
except OSError:
pass
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():
if not RunningInsideVim():
return sys.executable
import vim # NOQA
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' ]
if OnWindows():
# On Windows, 'pythonw' doesn't pop-up a console window like running
# 'python' does.
python_names.insert( 0, 'pythonw' )
path_to_python = 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 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 PathToFirstExistingExecutable( executable_name_list ):
for executable_name in executable_name_list:
path = find_executable( executable_name )
if path:
return path
return None
def OnWindows():
return sys.platform == 'win32'
# From here: http://stackoverflow.com/a/8536476/1672783
def TerminateProcess( pid ):
if OnWindows():
import ctypes
PROCESS_TERMINATE = 1
handle = ctypes.windll.kernel32.OpenProcess( PROCESS_TERMINATE,
False,
pid )
ctypes.windll.kernel32.TerminateProcess( handle, -1 )
ctypes.windll.kernel32.CloseHandle( handle )
else:
os.kill( pid, signal.SIGTERM )
def AddThirdPartyFoldersToSysPath():
path_to_third_party = os.path.join(
os.path.dirname( os.path.abspath( __file__ ) ),
'../../third_party' )
for folder in os.listdir( path_to_third_party ):
sys.path.insert( 0, os.path.realpath( os.path.join( path_to_third_party,
folder ) ) )
def ForceSemanticCompletion( request_data ):
return ( 'force_semantic' in request_data and
bool( request_data[ 'force_semantic' ] ) )
def SafePopen( args, bufsize = 0, executable = None, stdin = None,
stdout = None, stderr = None, preexec_fn = None,
close_fds = False, shell = False, cwd = None, env = None,
universal_newlines = False, startupinfo = None,
creationflags = 0 ):
if stdin is None:
# We need this on Windows otherwise bad things happen. See issue #637.
stdin = subprocess.PIPE if OnWindows() else None
return subprocess.Popen( args, bufsize, executable, stdin, stdout, stderr,
preexec_fn, close_fds, shell, cwd, env,
universal_newlines, startupinfo, creationflags )