def __init__(self): self.roots = [] self.priority_files = [] self.requests = AnalyzerQueue('requests') self.responses = AnalyzerQueue('responses') reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start()
class AnalysisServer(object): MAX_ID = 9999999 # Halts all worker threads until the server is ready. _ready_barrier = threading.Barrier(4, timeout=5) _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None @property def ready_barrier(self): return AnalysisServer._ready_barrier @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin @staticmethod def get_request_id(): with AnalysisServer._request_id_lock: if AnalysisServer._request_id >= AnalysisServer.MAX_ID: AnalysisServer._request_id = -1 AnalysisServer._request_id += 1 return str(AnalysisServer._request_id) @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def __init__(self): self.roots = [] self.priority_files = [] self.requests = RequestsQueue('requests') self.responses = AnalyzerQueue('responses') reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def add_root(self, path): """Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return new_root_path = find_pubspec_path(path) if not new_root_path: # It seems we're not in a pub package, so we're probably looking # at a loose .dart file. new_root_path = os.path.dirname(path) _logger.debug('did not find pubspec.yaml in path: %s', path) _logger.debug('set root to: %s', new_root_path) with AnalysisServer._op_lock: if new_root_path not in self.roots: _logger.debug('adding new root: %s', new_root_path) self.roots.append(new_root_path) self.send_set_roots(self.roots) return _logger.debug('root already known: %s', new_root_path) def start(self): if AnalysisServer.ping(): return self.send_get_version() sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer([sdk.path_to_dart, sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path)]) AnalysisServer.server.start(working_dir=sdk.path) self.start_stdout_watcher() try: # Server is ready. self.ready_barrier.wait() except threading.BrokenBarrierError: _logger.error('could not start server properly') return def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True # XXX: This is necessary. If we call t.start() directly, ST hangs. sublime.set_timeout_async(t.start, 0) def stop(self): req = requests.shut_down(str(AnalysisServer.MAX_ID + 100)) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, included=[], excluded=[]): req = AnalysisSetAnalysisRootsParams(included, excluded) _logger.info('sending set_roots request') self.requests.put(req.to_request(self.get_request_id()), block=False) def send_get_version(self): req = ServerGetVersionParams().to_request(self.get_request_id()) _logger.info('sending get version request') self.requests.put(req, block=False) def send_add_content(self, view): content = view.substr(sublime.Region(0, view.size())) req = AnalysisUpdateContentParams({view.file_name(): AddContentOverlay(content)}) _logger.info('sending update content request - add') # track this type of req as it may expire # TODO: when this file is saved, we must remove the overlays. self.requests.put(req.to_request(self.get_request_id()), view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): req = AnalysisUpdateContentParams({view.file_name(): RemoveContentOverlay()}) _logger.info('sending update content request - delete') self.requests.put(req.to_request(self.get_request_id()), view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, files): if files == self.priority_files: return req = AnalysisSetPriorityFilesParams(files) self.requests.put(req.to_request(self.get_request_id()), priority=TaskPriority.HIGH, block=False) req2 = AnalysisSetSubscriptionsParams({AnalysisService.NAVIGATION: files}) self.requests.put(req2.to_request(self.get_request_id()), priority=TaskPriority.HIGH, block=False)
class AnalysisServer(object): MAX_ID = 9999999 # Halts all worker threads until the server is ready. _ready_barrier = threading.Barrier(4, timeout=5) _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None @property def ready_barrier(self): return AnalysisServer._ready_barrier @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin @staticmethod def get_request_id(): with AnalysisServer._request_id_lock: if AnalysisServer._request_id >= AnalysisServer.MAX_ID: AnalysisServer._request_id = -1 AnalysisServer._request_id += 1 return AnalysisServer._request_id @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def __init__(self): self.roots = [] self.priority_files = [] self.requests = AnalyzerQueue('requests') self.responses = AnalyzerQueue('responses') reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def new_token(self): w = sublime.active_window() v = w.active_view() now = datetime.now() # 'c' indicates that this id was created at the client-side. token = w.id(), v.id(), '{}:{}:c{}'.format( w.id(), v.id(), AnalysisServer.get_request_id()) return token def add_root(self, path): """Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return p = find_pubspec_path(path) if not p: _logger.debug('did not found pubspec.yaml in path: %s', path) return with AnalysisServer._op_lock: if p not in self.roots: _logger.debug('adding new root: %s', p) self.roots.append(p) self.send_set_roots(self.roots) return _logger.debug('root already known: %s', p) def start(self): if AnalysisServer.ping(): return sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer([ 'dart', sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path) ]) AnalysisServer.server.start(working_dir=sdk.path) self.start_stdout_watcher() try: # Server is ready. self.ready_barrier.wait() except threading.BrokenBarrierError: _logger.error('could not start server properly') return def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True # XXX: This is necessary. If we call t.start() directly, ST hangs. sublime.set_timeout_async(t.start, 0) def stop(self): req = requests.shut_down(AnalysisServer.MAX_ID + 100) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, included=[], excluded=[]): _, _, token = self.new_token() req = requests.set_roots(token, included, excluded) _logger.info('sending set_roots request') self.requests.put(req, block=False) def send_find_top_level_decls(self, view, pattern): w_id, v_id, token = self.new_token() req = requests.find_top_level_decls(token, pattern) _logger.info('sending top level decls request') # TODO(guillermooo): Abstract this out. # track this type of req as it may expire g_req_to_resp['search']["{}:{}".format(w_id, v_id)] = token g_editor_context.search_id = token self.requests.put(req, view=view, priority=TaskPriority.HIGHEST, block=False) def send_find_element_refs(self, view, potential=False): if not view: return _, _, token = self.new_token() fname = view.file_name() offset = view.sel()[0].b req = requests.find_element_refs(token, fname, offset, potential) _logger.info('sending find_element_refs request') g_editor_context.search_id = token self.requests.put(req, view=view, priority=TaskPriority.HIGHEST, block=False) def send_add_content(self, view): w_id, v_id, token = self.new_token() data = { 'type': 'add', 'content': view.substr(sublime.Region(0, view.size())) } files = {view.file_name(): data} req = requests.update_content(token, files) _logger.info('sending update content request - add') # track this type of req as it may expire self.requests.put(req, view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): w_id, v_id, token = self.new_token() files = {view.file_name(): {"type": "remove"}} req = requests.update_content(token, files) _logger.info('sending update content request - delete') self.requests.put(req, view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, files): if files == self.priority_files: return w_id, v_id, token = self.new_token() _logger.info('sending set priority files request') req = requests.set_priority_files(token, files) self.requests.put(req, priority=TaskPriority.HIGH, block=False)
class AnalysisServer(object): MAX_ID = 9999999 # Halts all worker threads until the server is ready. _ready_barrier = threading.Barrier(4, timeout=5) _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None @property def ready_barrier(self): return AnalysisServer._ready_barrier @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin @staticmethod def get_request_id(): with AnalysisServer._request_id_lock: if AnalysisServer._request_id >= AnalysisServer.MAX_ID: AnalysisServer._request_id = -1 AnalysisServer._request_id += 1 return AnalysisServer._request_id @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def __init__(self): self.roots = [] self.priority_files = [] self.requests = AnalyzerQueue('requests') self.responses = AnalyzerQueue('responses') reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def new_token(self): w = sublime.active_window() v = w.active_view() now = datetime.now() # 'c' indicates that this id was created at the client-side. token = w.id(), v.id(), '{}:{}:c{}'.format(w.id(), v.id(), AnalysisServer.get_request_id()) return token def add_root(self, path): """Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return p = find_pubspec_path(path) if not p: _logger.debug('did not found pubspec.yaml in path: %s', path) return with AnalysisServer._op_lock: if p not in self.roots: _logger.debug('adding new root: %s', p) self.roots.append(p) self.send_set_roots(self.roots) return _logger.debug('root already known: %s', p) def start(self): if AnalysisServer.ping(): return sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer(['dart', sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path)]) AnalysisServer.server.start(working_dir=sdk.path) self.start_stdout_watcher() try: # Server is ready. self.ready_barrier.wait() except threading.BrokenBarrierError: _logger.error('could not start server properly') return def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True # XXX: This is necessary. If we call t.start() directly, ST hangs. sublime.set_timeout_async(t.start, 0) def stop(self): req = requests.shut_down(AnalysisServer.MAX_ID + 100) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, included=[], excluded=[]): _, _, token = self.new_token() req = requests.set_roots(token, included, excluded) _logger.info('sending set_roots request') self.requests.put(req, block=False) def send_find_top_level_decls(self, view, pattern): w_id, v_id, token = self.new_token() req = requests.find_top_level_decls(token, pattern) _logger.info('sending top level decls request') # TODO(guillermooo): Abstract this out. # track this type of req as it may expire g_req_to_resp['search']["{}:{}".format(w_id, v_id)] = token g_editor_context.search_id = token self.requests.put(req, view=view, priority=TaskPriority.HIGHEST, block=False) def send_find_element_refs(self, view, potential=False): if not view: return _, _, token = self.new_token() fname = view.file_name() offset = view.sel()[0].b req = requests.find_element_refs(token, fname, offset, potential) _logger.info('sending find_element_refs request') g_editor_context.search_id = token self.requests.put(req, view=view, priority=TaskPriority.HIGHEST, block=False) def send_add_content(self, view): w_id, v_id, token = self.new_token() data = {'type': 'add', 'content': view.substr(sublime.Region(0, view.size()))} files = {view.file_name(): data} req = requests.update_content(token, files) _logger.info('sending update content request - add') # track this type of req as it may expire self.requests.put(req, view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): w_id, v_id, token = self.new_token() files = {view.file_name(): {"type": "remove"}} req = requests.update_content(token, files) _logger.info('sending update content request - delete') self.requests.put(req, view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, files): if files == self.priority_files: return w_id, v_id, token = self.new_token() _logger.info('sending set priority files request') req = requests.set_priority_files(token, files) self.requests.put(req, priority=TaskPriority.HIGH, block=False)
def __init__(self): self.roots = [] self.priority_files = [] self.requests = RequestsQueue('requests') self.responses = AnalyzerQueue('responses') self.request_ids = RequestIdManager()
class AnalysisServer(object): MAX_ID = 9999999 _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None def __init__(self): self.roots = [] self.priority_files = [] self.requests = RequestsQueue('requests') self.responses = AnalyzerQueue('responses') self.request_ids = RequestIdManager() @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin def get_request_id(self, view, response_type): return self.request_ids.new_id(view, response_type) @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def start_handlers(self): reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def add_root(self, view, path): """ Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return new_root_path = find_pubspec_path(path) if not new_root_path: # It seems we're not in a pub package, so we're probably looking # at a loose .dart file. new_root_path = os.path.dirname(path) _logger.debug('did not find pubspec.yaml in path: %s', path) _logger.debug('set root to: %s', new_root_path) with AnalysisServer._op_lock: if new_root_path not in self.roots: _logger.debug('adding new root: %s', new_root_path) self.roots.append(new_root_path) self.send_set_roots(view, self.roots) return _logger.debug('root already known: %s', new_root_path) def start(self): if AnalysisServer.ping(): _logger.info('AnalysisServer is already running') return self.send_get_version() sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer([ sdk.path_to_dart, sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path), '--file-read-mode normalize-eol-always', ]) def do_start(): try: AnalysisServer.server.start(working_dir=sdk.path) self.start_handlers() self.start_stdout_watcher() except Exception as e: _logger.error('could not start server properly') _logger.error(e) return threading.Thread(target=do_start).start() def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True t.start() def stop(self): req = requests.shut_down(str(AnalysisServer.MAX_ID + 100)) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, view, included=[], excluded=[]): included = [f for f in included if not self.should_ignore_file(f)] if not (included or excluded): return req = AnalysisSetAnalysisRootsParams(included, excluded) _logger.info('sending set_roots request') self.requests.put(req.to_request( self.get_request_id(view, AnalysisSetAnalysisRootsResult)), block=False) def send_get_version(self, view=None): view = get_active_view() req = ServerGetVersionParams().to_request( self.get_request_id(view, ServerGetVersionResult)) _logger.info('sending get version request') self.requests.put(req, block=False) def send_add_content(self, view): if self.should_ignore_file(view.file_name()): return content = view.substr(sublime.Region(0, view.size())) req = AnalysisUpdateContentParams( {view.file_name(): AddContentOverlay(content)}) _logger.info('sending update content request - add') # track this type of req as it may expire # TODO: when this file is saved, we must remove the overlays. self.requests.put(req.to_request( self.get_request_id(view, AnalysisUpdateContentResult)), view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): if self.should_ignore_file(view.file_name()): return req = AnalysisUpdateContentParams( {view.file_name(): RemoveContentOverlay()}) _logger.info('sending update content request - delete') self.requests.put(req.to_request( self.get_request_id(view, AnalysisUpdateContentResult)), view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, view, files): if files == self.priority_files: return definite_files = [f for f in files if not self.should_ignore_file(f)] if not definite_files: return req = AnalysisSetPriorityFilesParams(definite_files) self.requests.put(req.to_request( self.get_request_id(view, AnalysisSetPriorityFilesResult)), priority=TaskPriority.HIGH, block=False) req2 = AnalysisSetSubscriptionsParams( {AnalysisService.NAVIGATION: definite_files}) self.requests.put(req2.to_request( self.get_request_id(view, ServerSetSubscriptionsResult)), priority=TaskPriority.HIGH, block=False) def send_get_suggestions(self, view, file, offset): new_id = self.get_request_id(view, CompletionGetSuggestionsResult) with editor_context.autocomplete_context as actx: actx.invalidate() actx.request_id = new_id req = CompletionGetSuggestionsParams(file, offset) req = req.to_request(new_id) self.requests.put(req, priority=TaskPriority.HIGH, block=False) def send_format_file(self, view): new_id = self.get_request_id(view, EditFormatResult) if not view.file_name(): _logger.info( "aborting sending request for formatting - no file name") return r0 = None try: r0 = view.sel()[0] except IndexError: r0 = sublime.Region(0) # TODO: Implement lineLength parameter. req = EditFormatParams(view.file_name(), r0.begin(), r0.size()) req = req.to_request(new_id) _logger.info("now sending request for formatting") self.requests.put(req, priority=TaskPriority.HIGH, block=False) def should_ignore_file(self, path): project = DartProject.from_path(path) is_a_third_party_file = (project and is_path_under( project.path_to_packages, path)) if is_a_third_party_file: return True sdk = SDK() return is_path_under(sdk.path, path)
class AnalysisServer(object): MAX_ID = 9999999 _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None def __init__(self): self.roots = [] self.priority_files = [] self.requests = RequestsQueue('requests') self.responses = AnalyzerQueue('responses') self.request_ids = RequestIdManager() @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin def get_request_id(self, view, response_type): return self.request_ids.new_id(view, response_type) @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def start_handlers(self): reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def add_root(self, view, path): """ Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return new_root_path = find_pubspec_path(path) if not new_root_path: # It seems we're not in a pub package, so we're probably looking # at a loose .dart file. new_root_path = os.path.dirname(path) _logger.debug('did not find pubspec.yaml in path: %s', path) _logger.debug('set root to: %s', new_root_path) with AnalysisServer._op_lock: if new_root_path not in self.roots: _logger.debug('adding new root: %s', new_root_path) self.roots.append(new_root_path) self.send_set_roots(view, self.roots) return _logger.debug('root already known: %s', new_root_path) def start(self): if AnalysisServer.ping(): _logger.info('AnalysisServer is already running') return self.send_get_version() sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer([sdk.path_to_dart, sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path), '--file-read-mode normalize-eol-always', ]) def do_start(): try: AnalysisServer.server.start(working_dir=sdk.path) self.start_handlers() self.start_stdout_watcher() except Exception as e: _logger.error('could not start server properly') _logger.error(e) return threading.Thread(target=do_start).start() def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True t.start() def stop(self): req = requests.shut_down(str(AnalysisServer.MAX_ID + 100)) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, view, included=[], excluded=[]): included = [f for f in included if not self.should_ignore_file(f)] if not (included or excluded): return req = AnalysisSetAnalysisRootsParams(included, excluded) _logger.info('sending set_roots request') self.requests.put(req.to_request(self.get_request_id(view, AnalysisSetAnalysisRootsResult)), block=False) def send_get_version(self, view=None): view = get_active_view() req = ServerGetVersionParams().to_request( self.get_request_id(view, ServerGetVersionResult)) _logger.info('sending get version request') self.requests.put(req, block=False) def send_add_content(self, view): if self.should_ignore_file(view.file_name()): return content = view.substr(sublime.Region(0, view.size())) req = AnalysisUpdateContentParams({view.file_name(): AddContentOverlay(content)}) _logger.info('sending update content request - add') # track this type of req as it may expire # TODO: when this file is saved, we must remove the overlays. self.requests.put(req.to_request(self.get_request_id(view, AnalysisUpdateContentResult)), view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): if self.should_ignore_file(view.file_name()): return req = AnalysisUpdateContentParams({view.file_name(): RemoveContentOverlay()}) _logger.info('sending update content request - delete') self.requests.put(req.to_request(self.get_request_id(view, AnalysisUpdateContentResult)), view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, view, files): if files == self.priority_files: return definite_files = [f for f in files if not self.should_ignore_file(f)] if not definite_files: return req = AnalysisSetPriorityFilesParams(definite_files) self.requests.put(req.to_request(self.get_request_id(view, AnalysisSetPriorityFilesResult)), priority=TaskPriority.HIGH, block=False) req2 = AnalysisSetSubscriptionsParams({AnalysisService.NAVIGATION: definite_files}) self.requests.put(req2.to_request(self.get_request_id(view, ServerSetSubscriptionsResult)), priority=TaskPriority.HIGH, block=False) def send_get_suggestions(self, view, file, offset): new_id = self.get_request_id(view, CompletionGetSuggestionsResult) with editor_context.autocomplete_context as actx: actx.invalidate() actx.request_id = new_id req = CompletionGetSuggestionsParams(file, offset) req = req.to_request(new_id) self.requests.put(req, priority=TaskPriority.HIGH, block=False) def send_format_file(self, view): new_id = self.get_request_id(view, EditFormatResult) if not view.file_name(): _logger.info("aborting sending request for formatting - no file name") return r0 = None try: r0 = view.sel()[0] except IndexError: r0 = sublime.Region(0) # TODO: Implement lineLength parameter. req = EditFormatParams(view.file_name(), r0.begin(), r0.size()) req = req.to_request(new_id) _logger.info("now sending request for formatting") self.requests.put(req, priority=TaskPriority.HIGH, block=False) def should_ignore_file(self, path): project = DartProject.from_path(path) is_a_third_party_file = (project and is_path_under(project.path_to_packages, path)) if is_a_third_party_file: return True sdk = SDK() return is_path_under(sdk.path, path)
class AnalysisServer(object): MAX_ID = 9999999 # Halts all worker threads until the server is ready. _ready_barrier = threading.Barrier(4, timeout=5) _request_id_lock = threading.Lock() _op_lock = threading.Lock() _write_lock = threading.Lock() _request_id = -1 server = None @property def ready_barrier(self): return AnalysisServer._ready_barrier @property def stdout(self): return AnalysisServer.server.proc.stdout @property def stdin(self): return AnalysisServer.server.proc.stdin @staticmethod def get_request_id(): with AnalysisServer._request_id_lock: if AnalysisServer._request_id >= AnalysisServer.MAX_ID: AnalysisServer._request_id = -1 AnalysisServer._request_id += 1 return str(AnalysisServer._request_id) @staticmethod def ping(): try: return AnalysisServer.server.is_running except AttributeError: return def __init__(self): self.roots = [] self.priority_files = [] self.requests = RequestsQueue('requests') self.responses = AnalyzerQueue('responses') reqh = RequestHandler(self) reqh.daemon = True reqh.start() resh = ResponseHandler(self) resh.daemon = True resh.start() @property def proc(self): return AnalysisServer.server def add_root(self, path): """Adds `path` to the monitored roots if it is unknown. If a `pubspec.yaml` is found in the path, its parent is monitored. Otherwise the passed-in directory name is monitored. @path Can be a directory or a file path. """ if not path: _logger.debug('not a valid path: %s', path) return new_root_path = find_pubspec_path(path) if not new_root_path: # It seems we're not in a pub package, so we're probably looking # at a loose .dart file. new_root_path = os.path.dirname(path) _logger.debug('did not find pubspec.yaml in path: %s', path) _logger.debug('set root to: %s', new_root_path) with AnalysisServer._op_lock: if new_root_path not in self.roots: _logger.debug('adding new root: %s', new_root_path) self.roots.append(new_root_path) self.send_set_roots(self.roots) return _logger.debug('root already known: %s', new_root_path) def start(self): if AnalysisServer.ping(): return self.send_get_version() sdk = SDK() _logger.info('starting AnalysisServer') AnalysisServer.server = PipeServer([sdk.path_to_dart, sdk.path_to_analysis_snapshot, '--sdk={0}'.format(sdk.path)]) AnalysisServer.server.start(working_dir=sdk.path) self.start_stdout_watcher() try: # Server is ready. self.ready_barrier.wait() except threading.BrokenBarrierError: _logger.error('could not start server properly') return def start_stdout_watcher(self): sdk = SDK() t = StdoutWatcher(self, sdk.path) # Thread dies with the main thread. t.daemon = True # XXX: This is necessary. If we call t.start() directly, ST hangs. sublime.set_timeout_async(t.start, 0) def stop(self): req = requests.shut_down(str(AnalysisServer.MAX_ID + 100)) self.requests.put(req, priority=TaskPriority.HIGHEST, block=False) self.requests.put({'_internal': _SIGNAL_STOP}, block=False) self.responses.put({'_internal': _SIGNAL_STOP}, block=False) # self.server.stop() def write(self, data): with AnalysisServer._write_lock: data = (json.dumps(data) + '\n').encode('utf-8') _logger.debug('writing to stdin: %s', data) self.stdin.write(data) self.stdin.flush() def send_set_roots(self, included=[], excluded=[]): included = [f for f in included if not self.should_ignore_file(f)] if not (included or excluded): return req = AnalysisSetAnalysisRootsParams(included, excluded) _logger.info('sending set_roots request') self.requests.put(req.to_request(self.get_request_id()), block=False) def send_get_version(self): req = ServerGetVersionParams().to_request(self.get_request_id()) _logger.info('sending get version request') self.requests.put(req, block=False) def send_add_content(self, view): if self.should_ignore_file(view.file_name()): return content = view.substr(sublime.Region(0, view.size())) req = AnalysisUpdateContentParams({view.file_name(): AddContentOverlay(content)}) _logger.info('sending update content request - add') # track this type of req as it may expire # TODO: when this file is saved, we must remove the overlays. self.requests.put(req.to_request(self.get_request_id()), view=view, priority=TaskPriority.HIGH, block=False) def send_remove_content(self, view): if self.should_ignore_file(view.file_name()): return req = AnalysisUpdateContentParams({view.file_name(): RemoveContentOverlay()}) _logger.info('sending update content request - delete') self.requests.put(req.to_request(self.get_request_id()), view=view, priority=TaskPriority.HIGH, block=False) def send_set_priority_files(self, files): if files == self.priority_files: return definite_files = [f for f in files if not self.should_ignore_file(f)] if not definite_files: return req = AnalysisSetPriorityFilesParams(definite_files) self.requests.put(req.to_request(self.get_request_id()), priority=TaskPriority.HIGH, block=False) req2 = AnalysisSetSubscriptionsParams({AnalysisService.NAVIGATION: definite_files}) self.requests.put(req2.to_request(self.get_request_id()), priority=TaskPriority.HIGH, block=False) def should_ignore_file(self, path): project = DartProject.from_path(path) is_a_third_party_file = (project and is_path_under(project.path_to_packages, path)) if is_a_third_party_file: return True sdk = SDK() return is_path_under(sdk.path, path)