def _ReadMessage( self ): """Read a response message from TSServer.""" # The headers are pretty similar to HTTP. # At the time of writing, 'Content-Length' is the only supplied header. headers = {} while True: headerline = self._tsserver_handle.stdout.readline().strip() if not headerline: break key, value = utils.ToUnicode( headerline ).split( ':', 1 ) headers[ key.strip() ] = value.strip() # The response message is a JSON object which comes back on one line. # Since this might change in the future, we use the 'Content-Length' # header. if 'Content-Length' not in headers: raise RuntimeError( "Missing 'Content-Length' header" ) contentlength = int( headers[ 'Content-Length' ] ) # TSServer adds a newline at the end of the response message and counts it # as one character (\n) towards the content length. However, newlines are # two characters on Windows (\r\n), so we need to take care of that. See # issue https://github.com/Microsoft/TypeScript/issues/3403 content = self._tsserver_handle.stdout.read( contentlength ) if utils.OnWindows() and content.endswith( b'\r' ): content += self._tsserver_handle.stdout.read( 1 ) return json.loads( utils.ToUnicode( content ) )
def _HasCompletionsThatCouldBeCompletedWithMoreText(self, completions): completed_item = vimsupport.GetVariableValue('v:completed_item') if not completed_item: return False completed_word = utils.ToUnicode(completed_item['word']) if not completed_word: return False # Sometimes CompleteDone is called after the next character is inserted. # If so, use inserted character to filter possible completions further. text = vimsupport.TextBeforeCursor() reject_exact_match = True if text and text[-1] != completed_word[-1]: reject_exact_match = False completed_word += text[-1] for completion in completions: word = utils.ToUnicode( ConvertCompletionDataToVimData(completion)['word']) if reject_exact_match and word == completed_word: continue if word.startswith(completed_word): return True return False
def _SetUpServer( self ): self._available_completers = {} self._user_notified_about_crash = False self._filetypes_with_keywords_loaded = set() self._server_is_ready_with_cache = False self._message_poll_request = None self._user_options = base.GetUserOptions() self._omnicomp = OmniCompleter( self._user_options ) self._buffers = BufferDict( self._user_options ) self._SetLogLevel() hmac_secret = os.urandom( HMAC_SECRET_LENGTH ) options_dict = dict( self._user_options ) options_dict[ 'hmac_secret' ] = utils.ToUnicode( base64.b64encode( hmac_secret ) ) options_dict[ 'server_keep_logfiles' ] = self._user_options[ 'keep_logfiles' ] # The temp options file is deleted by ycmd during startup. with NamedTemporaryFile( delete = False, mode = 'w+' ) as options_file: json.dump( options_dict, options_file ) server_port = utils.GetUnusedLocalhostPort() BaseRequest.server_location = 'http://127.0.0.1:' + str( server_port ) BaseRequest.hmac_secret = hmac_secret try: python_interpreter = paths.PathToPythonInterpreter() except RuntimeError as error: error_message = ( "Unable to start the ycmd server. {0}. " "Correct the error then restart the server " "with ':YcmRestartServer'.".format( str( error ).rstrip( '.' ) ) ) self._logger.exception( error_message ) vimsupport.PostVimMessage( error_message ) return args = [ python_interpreter, paths.PathToServerScript(), '--port={0}'.format( server_port ), '--options_file={0}'.format( options_file.name ), '--log={0}'.format( self._user_options[ 'log_level' ] ), '--idle_suicide_seconds={0}'.format( SERVER_IDLE_SUICIDE_SECONDS ) ] self._server_stdout = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format( port = server_port, std = 'stdout' ) ) self._server_stderr = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format( port = server_port, std = 'stderr' ) ) args.append( '--stdout={0}'.format( self._server_stdout ) ) args.append( '--stderr={0}'.format( self._server_stderr ) ) if self._user_options[ 'keep_logfiles' ]: args.append( '--keep_logfiles' ) self._server_popen = utils.SafePopen( args, stdin_windows = PIPE, stdout = PIPE, stderr = PIPE )
def _GoToDefinition(self, request_data): def find_end_of_command(line, match): if match is None: return -1 for i in range(match.start(), len(line)): e = line[i] if e == "}": return i return -1 line = utils.ToUnicode(request_data["line_value"]) match = self._ref_reg.search(line) end_of_command = find_end_of_command(line, match) if end_of_command == -1: raise RuntimeError( 'Can\'t jump to definition or declaration: not implemented yet' ) else: ref = line[match.end():end_of_command] if ref not in self._goto_labels: raise RuntimeError( 'Can\'t jump to definition or declaration: not implemented yet' ) filename, line, col = self._goto_labels[ref] return responses.BuildGoToResponse(filename, line, col)
def ShouldUseNow(self, request_data): self._omnifunc = utils.ToUnicode(vimsupport.Eval('&omnifunc')) if not self._omnifunc: return False if self.ShouldUseCache(): return super(OmniCompleter, self).ShouldUseNow(request_data) return self.ShouldUseNowInner(request_data)
def _NotifyUserIfServerCrashed(self): if self._user_notified_about_crash or self.IsServerAlive(): return self._user_notified_about_crash = True return_code = self._server_popen.poll() if return_code == server_utils.CORE_UNEXPECTED_STATUS: error_message = CORE_UNEXPECTED_MESSAGE elif return_code == server_utils.CORE_MISSING_STATUS: error_message = CORE_MISSING_MESSAGE elif return_code == server_utils.CORE_PYTHON2_STATUS: error_message = CORE_PYTHON2_MESSAGE elif return_code == server_utils.CORE_PYTHON3_STATUS: error_message = CORE_PYTHON3_MESSAGE elif return_code == server_utils.CORE_OUTDATED_STATUS: error_message = CORE_OUTDATED_MESSAGE else: error_message = EXIT_CODE_UNEXPECTED_MESSAGE.format( code=return_code) server_stderr = '\n'.join( utils.ToUnicode(self._server_popen.stderr.read()).splitlines()) if server_stderr: self._logger.error(server_stderr) error_message = SERVER_SHUTDOWN_MESSAGE + ' ' + error_message self._logger.error(error_message) vimsupport.PostVimMessage(error_message)
def _SetUpServer(self): self._available_completers = {} self._user_notified_about_crash = False self._filetypes_with_keywords_loaded = set() self._server_is_ready_with_cache = False self._message_poll_request = None base.LoadJsonDefaultsIntoVim() user_options_store.SetAll(base.BuildServerConf()) self._user_options = user_options_store.GetAll() self._omnicomp = OmniCompleter(self._user_options) self._buffers = BufferDict(self._user_options) self._SetLogLevel() hmac_secret = os.urandom(HMAC_SECRET_LENGTH) options_dict = dict(self._user_options) options_dict['hmac_secret'] = utils.ToUnicode( base64.b64encode(hmac_secret)) options_dict['server_keep_logfiles'] = self._user_options[ 'keep_logfiles'] # The temp options file is deleted by ycmd during startup. with NamedTemporaryFile(delete=False, mode='w+') as options_file: json.dump(options_dict, options_file) server_port = utils.GetUnusedLocalhostPort() BaseRequest.server_location = 'http://127.0.0.1:' + str(server_port) BaseRequest.hmac_secret = hmac_secret this_file_path = os.path.dirname(os.path.realpath(__file__)) tabnine_binary_path = os.path.join(this_file_path, '../../binaries/') args = [ '--client=vim', '--port={0}'.format(server_port), '--options_file={0}'.format(options_file.name), '--log={0}'.format(self._user_options['log_level']), '--idle_suicide_seconds={0}'.format(SERVER_IDLE_SUICIDE_SECONDS) ] self._server_stdout = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stdout')) self._server_stderr = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stderr')) args.append('--stdout={0}'.format(self._server_stdout)) args.append('--stderr={0}'.format(self._server_stderr)) if self._user_options['keep_logfiles']: args.append('--keep_logfiles') try: self._server_popen = start_tabnine_proc( cmd_args=args, binary_dir=tabnine_binary_path) except RuntimeError as error: error_message = str(error) self._logger.exception(error_message) vimsupport.PostVimMessage(error_message) return
def _HasCompletionsThatCouldBeCompletedWithMoreText_OlderVim( self, completions ): # No support for multiple line completions text = vimsupport.TextBeforeCursor() for completion in completions: word = utils.ToUnicode( ConvertCompletionDataToVimData( completion )[ 'word' ] ) for i in range( 1, len( word ) - 1 ): # Excluding full word if text[ -1 * i : ] == word[ : i ]: return True return False
def _WorkspaceDirForProject(project_dir, use_clean_workspace): if use_clean_workspace: temp_path = os.path.join(WORKSPACE_ROOT_PATH, 'temp') try: os.makedirs(temp_path) except OSError: pass return tempfile.mkdtemp(dir=temp_path) project_dir_hash = hashlib.sha256(utils.ToBytes(project_dir)) return os.path.join(WORKSPACE_ROOT_PATH, utils.ToUnicode(project_dir_hash.hexdigest()))
def _SetupServer(self): self._available_completers = {} self._user_notified_about_crash = False self._filetypes_with_keywords_loaded = set() self._server_is_ready_with_cache = False server_port = utils.GetUnusedLocalhostPort() # The temp options file is deleted by ycmd during startup with NamedTemporaryFile(delete=False, mode='w+') as options_file: hmac_secret = os.urandom(HMAC_SECRET_LENGTH) options_dict = dict(self._user_options) options_dict['hmac_secret'] = utils.ToUnicode( base64.b64encode(hmac_secret)) options_dict['server_keep_logfiles'] = self._user_options[ 'keep_logfiles'] json.dump(options_dict, options_file) options_file.flush() args = [ paths.PathToPythonInterpreter(), paths.PathToServerScript(), '--port={0}'.format(server_port), '--options_file={0}'.format(options_file.name), '--log={0}'.format(self._user_options['log_level']), '--idle_suicide_seconds={0}'.format( SERVER_IDLE_SUICIDE_SECONDS) ] self._server_stdout = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stdout')) self._server_stderr = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stderr')) args.append('--stdout={0}'.format(self._server_stdout)) args.append('--stderr={0}'.format(self._server_stderr)) if self._user_options['keep_logfiles']: args.append('--keep_logfiles') self._server_popen = utils.SafePopen(args, stdin_windows=PIPE, stdout=PIPE, stderr=PIPE) BaseRequest.server_location = 'http://127.0.0.1:' + str( server_port) BaseRequest.hmac_secret = hmac_secret self._NotifyUserIfServerCrashed()
def ShouldUseNowInner(self, request_data): #q = utils.ToUtf8IfNeeded(request_data['query']) #col = request_data["start_column"] line = utils.ToUnicode(request_data["line_value"]) if self._main_directory is None: self._ComputeMainDirectory(request_data) should_use = False line_splitted = line match = self._cite_reg.search(line_splitted) if match is not None: self._completion_target = 'cite' should_use = True match = self._ref_reg.search(line_splitted) if match is not None: if self._completion_target == 'cite': self._completion_target = 'all' else: self._completion_target = 'label' should_use = True return should_use
def ToUnicode_Str_test(): value = utils.ToUnicode(u'abc') eq_(value, u'abc') ok_(isinstance(value, str))
def ToUnicode_Bytes_test(): value = utils.ToUnicode(bytes(b'abc')) eq_(value, u'abc') ok_(isinstance(value, str))
def ToUnicode_Py2FutureStr_test(): value = utils.ToUnicode(str('abc')) eq_(value, u'abc') ok_(isinstance(value, str))
def matcher(key): return (utils.ToUnicode(completed.get(key, "")) == utils.ToUnicode( item.get(key, "")))
def OnFileReadyToParse(self, request_data): self._omnifunc = utils.ToUnicode(vim.eval('&omnifunc'))
def test_ToUnicode_Int(self): value = utils.ToUnicode(123) assert_that(value, equal_to(u'123')) assert_that(isinstance(value, str))
def test_ToUnicode_None(self): value = utils.ToUnicode(None) assert_that(value, equal_to(u'')) assert_that(isinstance(value, str))
def _GetCommandOutput(command): return utils.ToUnicode( utils.SafePopen(command, stdin_windows=PIPE, stdout=PIPE, stderr=PIPE).communicate()[0].rstrip())
def test_ToUnicode_Str(self): value = utils.ToUnicode(u'abc') assert_that(value, equal_to(u'abc')) assert_that(isinstance(value, str))
def GetTextPropertyTypes( *args, **kwargs ): return [ utils.ToUnicode( p ) for p in vim.eval( 'prop_type_list()' ) ]
def ToUnicode_Int_test(): value = utils.ToUnicode(123) eq_(value, u'123') ok_(isinstance(value, str))
def UpdateSignatureHelp(state, signature_info): # noqa if not ShouldUseSignatureHelp(): return state signatures = signature_info.get('signatures') or [] if not signatures: if state.popup_win_id: # TODO/FIXME: Should we use popup_hide() instead ? vim.eval(f"popup_close( { state.popup_win_id } )") return SignatureHelpState(None, SignatureHelpState.INACTIVE) if state.state != SignatureHelpState.ACTIVE: state.anchor = vimsupport.CurrentLineAndColumn() state.state = SignatureHelpState.ACTIVE # Generate the buffer as a list of lines buf_lines = _MakeSignatureHelpBuffer(signature_info) screen_pos = vimsupport.ScreenPositionForLineColumnInWindow( vim.current.window, state.anchor[0] + 1, # anchor 0-based state.anchor[1] + 1) # anchor 0-based # Simulate 'flip' at the screen boundaries by using screenpos and hiding the # signature help menu if it overlaps the completion popup (pum). # # FIXME: revert to cursor-relative positioning and the 'flip' option when that # is implemented (if that is indeed better). # By default display above the anchor line = int(screen_pos['row']) - 1 # -1 to display above the cur line pos = "botleft" cursor_line = vimsupport.CurrentLineAndColumn()[0] + 1 if int(screen_pos['row']) <= len(buf_lines): # No room at the top, display below line = int(screen_pos['row']) + 1 pos = "topleft" # Don't allow the popup to overlap the cursor if (pos == 'topleft' and line < cursor_line and line + len(buf_lines) >= cursor_line): line = 0 # Don't allow the popup to overlap the pum if line > 0 and GetIntValue('pumvisible()'): pum_line = GetIntValue('pum_getpos().row') + 1 if pos == 'botleft' and pum_line <= line: line = 0 elif (pos == 'topleft' and pum_line >= line and pum_line < (line + len(buf_lines))): line = 0 if line <= 0: # Nowhere to put it so hide it if state.popup_win_id: # TODO/FIXME: Should we use popup_hide() instead ? vim.eval(f"popup_close( { state.popup_win_id } )") return SignatureHelpState(None, SignatureHelpState.INACTIVE) if int(screen_pos['curscol']) <= 1: col = 1 else: # -1 for padding, # -1 for the trigger character inserted (the anchor is set _after_ the # character is inserted, so we remove it). # FIXME: multi-byte characters would be wrong. Need to set anchor before # inserting the char ? col = int(screen_pos['curscol']) - 2 if col <= 0: col = 1 options = { "line": line, "col": col, "pos": pos, "wrap": 0, # NOTE: We *dont'* use "cursorline" here - that actually uses PMenuSel, # which is just too invasive for us (it's more selected item than actual # cursorline. So instead, we manually set 'cursorline' in the popup window # and enable sytax based on the current file syntax) "flip": 1, "padding": [0, 1, 0, 1], # Pad 1 char in X axis to match completion menu } if not state.popup_win_id: state.popup_win_id = GetIntValue( f'popup_create( { json.dumps( buf_lines ) }, ' f'{ json.dumps( options ) } )') else: vim.eval(f'popup_settext( { state.popup_win_id }, ' f'{ json.dumps( buf_lines ) } )') # Should do nothing if already visible vim.eval( f'popup_move( { state.popup_win_id }, { json.dumps( options ) } )') vim.eval(f'popup_show( { state.popup_win_id } )') syntax = utils.ToUnicode(vim.current.buffer.options['syntax']) active_signature = int(signature_info.get('activeSignature', 0)) vim.eval(f"win_execute( { state.popup_win_id }, " f"'set syntax={ syntax } cursorline | " f"call cursor( [ { active_signature + 1 }, 1 ] )' )") return state
def OnBufferUnload(self, deleted_buffer_file): SendEventNotificationAsync( 'BufferUnload', filepath=utils.ToUnicode(deleted_buffer_file))
def ToUnicode_Bytes_test(): value = utils.ToUnicode(bytes(b'abc')) assert_that(value, equal_to(u'abc')) assert_that(isinstance(value, str))
def ToUnicode_None_test(): value = utils.ToUnicode(None) eq_(value, u'') ok_(isinstance(value, str))
def _SetUpServer(self): self._available_completers = {} self._user_notified_about_crash = False self._filetypes_with_keywords_loaded = set() self._server_is_ready_with_cache = False self._message_poll_requests = {} self._latest_completion_request = None self._latest_signature_help_request = None self._signature_help_available_requests = SigHelpAvailableByFileType() self._latest_command_reqeust = None self._signature_help_state = signature_help.SignatureHelpState() self._user_options = base.GetUserOptions(self._default_options) self._omnicomp = OmniCompleter(self._user_options) self._buffers = BufferDict(self._user_options) self._SetLogLevel() hmac_secret = os.urandom(HMAC_SECRET_LENGTH) options_dict = dict(self._user_options) options_dict['hmac_secret'] = utils.ToUnicode( base64.b64encode(hmac_secret)) options_dict['server_keep_logfiles'] = self._user_options[ 'keep_logfiles'] # The temp options file is deleted by ycmd during startup. with NamedTemporaryFile(delete=False, mode='w+') as options_file: json.dump(options_dict, options_file) server_port = utils.GetUnusedLocalhostPort() BaseRequest.server_location = 'http://127.0.0.1:' + str(server_port) BaseRequest.hmac_secret = hmac_secret try: python_interpreter = paths.PathToPythonInterpreter() except RuntimeError as error: error_message = ( f"Unable to start the ycmd server. { str( error ).rstrip( '.' ) }. " "Correct the error then restart the server " "with ':YcmRestartServer'.") self._logger.exception(error_message) vimsupport.PostVimMessage(error_message) return args = [ python_interpreter, paths.PathToServerScript(), f'--port={ server_port }', f'--options_file={ options_file.name }', f'--log={ self._user_options[ "log_level" ] }', f'--idle_suicide_seconds={ SERVER_IDLE_SUICIDE_SECONDS }' ] self._server_stdout = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stdout')) self._server_stderr = utils.CreateLogfile( SERVER_LOGFILE_FORMAT.format(port=server_port, std='stderr')) args.append(f'--stdout={ self._server_stdout }') args.append(f'--stderr={ self._server_stderr }') if self._user_options['keep_logfiles']: args.append('--keep_logfiles') if 'YCM_WITH_PTVSD' in os.environ: args[1:1] = [ '-m', 'ptvsd', '--host', 'localhost', '--port', '1234', '--wait', '--no-subprocesses' ] self._logger.debug('Starting ycmd with: %s', args) self._server_popen = utils.SafePopen(args, stdin_windows=PIPE, stdout=PIPE, stderr=PIPE)