def _validate(ls: LanguageServer, uri: str): # Jedi script = get_script(ls, uri) result = [ types.Diagnostic(types.Range( types.Position(x.line - 1, x.column), types.Position(x.until_line - 1, x.until_column)), 'Invalid syntax', types.DiagnosticSeverity.Error, source='jedi') for x in script.get_syntax_errors() ] if result: ls.publish_diagnostics(uri, result) return # pyflakes pyflakes_check(script._code, script.path, PyflakesReporter(result, script, config['pyflakes_errors'])) # pycodestyle codestyleopts = get_pycodestyle_options(ls, uri) CodestyleChecker(script.path, script._code.splitlines(True), codestyleopts, CodestyleReport(codestyleopts, result)).check_all() if config['mypy_enabled']: try: _mypy_check(ls, uri, script, result) except Exception as e: ls.show_message(f'mypy check error: {e}', types.MessageType.Warning) ls.publish_diagnostics(uri, result)
async def parseAndSendDiagnostics( ls: LanguageServer, uri: str, ) -> None: await asyncio.sleep(DEBOUNCE_DELAY) diagnostics = [] async for diag in diagnostic.getDiagnostics(ls, uri): diagnostics.append(diag) ls.publish_diagnostics(uri, diagnostics)
def _diagnose(english_server: LanguageServer, params): # Get document from workspace text_doc = english_server.workspace.get_document(params.textDocument.uri) raw_results = proselint.tools.lint(text_doc.source) diagnostics = [] for _, message, line, col, _, _, length, _, _ in raw_results: diagnostics += [ Diagnostic( range=Range(Position(line, col - 1), Position(line, col + length)), message=message, severity=DiagnosticSeverity.Warning, source="eng-lsp", ) ] # Send diagnostics english_server.publish_diagnostics(params.textDocument.uri, diagnostics)
class Server: def __init__( self, method: ConnectionMethod, host: Optional[str], port: Optional[int] ) -> None: self._method = method self._host = host self._port = port if self._method == ConnectionMethod.TCP: if host is None or port is None: raise ValueError("host and port is required when method is TCP") self._server = LanguageServer() self._config = LanguageServerConfiguration.default() self._workspace = Workspace(self._server) self._register_command( Commands.ReloadServerConfiguration, self._on_reload_server_config, ) self._register_command( Commands.LintDocument, self._on_lint_document, ) self._register_command( Commands.FormatDocument, self._on_format_document, ) self._register_command( Commands.LintWorkspace, self._on_lint_workspace, ) self._register_command( Commands.FormatWorkspace, self._on_format_workspace, ) self._register_feature("$/setTrace", None, lambda *args, **kwargs: None) self._register_feature( lsp.methods.INITIALIZE, None, self._on_initialize, ) self._register_feature( lsp.methods.WORKSPACE_DID_CHANGE_CONFIGURATION, None, self._on_workspace_did_change_configuration, ) self._register_feature( lsp.methods.FORMATTING, lsp.types.DocumentFormattingOptions(), self._on_formatting, ) self._register_feature( lsp.methods.TEXT_DOCUMENT_DID_SAVE, None, self._on_text_document_did_save, ) self._register_feature( lsp.methods.TEXT_DOCUMENT_DID_OPEN, None, self._on_text_document_did_open, ) self._register_feature( lsp.methods.TEXT_DOCUMENT_DID_CLOSE, None, self._on_text_document_did_close, ) self._register_feature( lsp.methods.TEXT_DOCUMENT_DID_CHANGE, None, self._on_text_document_did_change, ) self._register_feature( lsp.methods.CODE_ACTION, lsp.types.CodeActionOptions( code_action_kinds=[lsp.types.CodeActionKind.QuickFix] ), self._provide_code_action, ) def _register_command(self, command_name: str, handler: Callable[..., Any]) -> None: @self._server.command(command_name) def cb(*args: Any, **kwargs: Any) -> Any: return handler(*args, **kwargs) def _register_feature( self, feature_name: str, option: Any, handler: Callable[..., Any] ) -> None: # NOTE: pygls calls setattr in `feature` decorator to add their own field. # Since a method doesn't allow setattr for undefined fields, # we cannot use it for the decorator. # Thus We define temporary function instead. @self._server.feature(feature_name, option) def cb(*args: Any, **kwargs: Any) -> Any: return handler(*args, **kwargs) def _on_config_received(self, data: Any) -> None: try: self._config = LanguageServerConfiguration.parse_obj(data[0]) except ValidationError as e: self._server.show_message_log(f"Error occurred: {e}") except Exception as e: self._server.show_message_log(f"Error occurred: {e}") def _request_config(self) -> None: self._server.get_configuration( lsp.types.ConfigurationParams( items=[ lsp.types.ConfigurationItem( scope_uri="", section=CONFIGURATION_SECTION_NAME ) ] ), self._on_config_received, ) def _on_initialize(self, params: lsp.types.InitializeParams) -> None: # NOTE: The return value from this method will be ignored. # pygls.LanguageServerProtocol provides some predefined lsp features. # It calls methods starting with `bf_`, then call use defined methods. # User defined methods are wrapped by the decorator in pygls, # and it doesn't use the return values from the methods. # See: https://github.com/openlawlibrary/pygls/blob/b5dcfa36ee3fab2cd0f3bf29248d58f5ad3b6796/pygls/protocol.py#L62-L75 # NOQA options = params.initialization_options if options is not None: config = options.get("config", None) if config is not None: self._on_config_received([config]) def _on_workspace_did_change_configuration( self, params: lsp.types.DidChangeConfigurationParams ) -> None: settings = params.settings if settings is not None and isinstance(settings, dict): config = settings.get("config", None) if config is not None: self._on_config_received([config]) def _publish_file_diagnostics( self, targets: Sequence[str], runtime: FileRuntime, ) -> None: for target in targets: runtime.update_diagnostics(target, None) diagnostics = runtime.get_diagnostics() self._server.publish_diagnostics( runtime.uri, diagnostics, ) def _publish_workspace_diagnostics( self, targets: Sequence[str], runtime: WorkspaceRuntime, ) -> None: for target in targets: runtime.update_diagnostics(target) to_publish: DefaultDict[str, List[Diagnostic]] = collections.defaultdict(list) data = list(runtime.iter_diagnostics()) for d in data: to_publish[d.uri].append(d.diagnostic) for uri, diagnostics in to_publish.items(): self._server.publish_diagnostics( uri, diagnostics, ) def _on_reload_server_config(self, *args: Any) -> None: self._request_config() def _handle_document_command(self, request: Any, targets: Sequence[str]) -> None: uri = _get_request_params(request) if uri is None: return runtime = self._workspace.create_file_runtime(uri, force=True) if runtime is None: return self._publish_file_diagnostics(targets, runtime) def _on_formatting(self, params: lsp.types.DocumentFormattingParams) -> None: # TODO: Consider adding unregistration config of this capability # for someone who wants opt-out this feature. uri = params.text_document.uri self._handle_document_command([uri], self._config.format_targets) def _on_lint_document(self, args: Any) -> None: self._handle_document_command(args, self._config.lint_targets) def _on_format_document(self, args: Any) -> None: self._handle_document_command(args, self._config.format_targets) def _handle_workspace_command(self, request: Any, targets: Sequence[str]) -> None: root_uri = self._server.workspace.root_uri root_path = self._server.workspace.root_path if root_uri is None or root_path is None: self._server.show_message( "workspace is not opened", lsp.types.MessageType.Error ) return runtime = self._workspace.get_workspace_runtime( root_uri, pathlib.Path(root_path) ) if runtime is None: return self._publish_workspace_diagnostics(targets, runtime) def _on_lint_workspace(self, args: Any) -> None: self._handle_workspace_command(args, self._config.lint_targets) def _on_format_workspace(self, args: Any) -> None: self._handle_workspace_command(args, self._config.format_targets) def _on_text_document_did_open( self, params: lsp.types.DidOpenTextDocumentParams ) -> None: uri = params.text_document.uri runtime = self._workspace.create_file_runtime(uri) if runtime is None: return self._publish_file_diagnostics(self._config.lint_targets, runtime) def _on_text_document_did_close( self, params: lsp.types.DidCloseTextDocumentParams ) -> None: pass def _on_text_document_did_save( self, params: lsp.types.DidSaveTextDocumentParams ) -> None: if not self._config.enable_lint_on_save: return None runtime = self._workspace.get_file_runtime(params.text_document.uri) if runtime is None: return self._publish_file_diagnostics(self._config.lint_targets, runtime) def _on_text_document_did_change( self, params: lsp.types.DidChangeTextDocumentParams, ) -> None: runtime = self._workspace.get_file_runtime(params.text_document.uri) if runtime is None: return changes = params.content_changes for change in changes: if not isinstance(change, lsp.types.TextDocumentContentChangeEvent): continue change_range = change.range if change_range is None: continue runtime.update_diagnostics_range(change_range, change.text) def _provide_code_action( self, params: lsp.types.CodeActionParams ) -> Optional[Sequence[Union[lsp.types.Command, lsp.types.CodeAction]]]: if not self._config.enable_code_action: return None runtime = self._workspace.get_file_runtime(params.text_document.uri) if runtime is None: return [] return runtime.query_code_actions(params.range) def start(self) -> None: _logger.info("starting server") if self._method == ConnectionMethod.IO: _logger.info("use stdio for the communication") self._server.start_io() else: assert self._method == ConnectionMethod.TCP, self._method _logger.info("use tcp for the communication") assert self._host is not None assert self._port is not None self._server.start_tcp(self._host, self._port)
def _publish_diagnostics(server: LanguageServer, uri: str): """Helper function to publish diagnostics for a file""" jedi_script = jedi_utils.script(server.workspace, uri) errors = jedi_script.get_syntax_errors() diagnostics = [jedi_utils.lsp_diagnostic(error) for error in errors] server.publish_diagnostics(uri, diagnostics)