module Steep module Server class Master module LSP = LanguageServer::Protocol class TypeCheckRequest attr_reader guid: String attr_reader library_paths: Set[Pathname] attr_reader signature_paths: Set[Pathname] attr_reader code_paths: Set[Pathname] attr_reader priority_paths: Set[Pathname] attr_reader checked_paths: Set[Pathname] def initialize: (guid: String) -> void def uri: (Pathname path) -> URI::File def as_json: (assignment: Services::PathAssignment) -> { guid: String, library_uris: Array[String], signature_uris: Array[String], code_uris: Array[String], priority_uris: Array[String] } def total: () -> Integer def percentage: () -> Integer def all_paths: () -> Set[Pathname] def checking_path?: (Pathname path) -> bool def checked: (Pathname path) -> void def finished?: () -> bool def unchecked_paths: () -> Set[Pathname] def unchecked_code_paths: () -> Set[Pathname] def unchecked_library_paths: () -> Set[Pathname] def unchecked_signature_paths: () -> Set[Pathname] end # TypeCheckController remembers changed files, keep track of open editors, and make a TypeCheckRequest that contains list of all files to be type checked # # ```rb # controller = TypeCheckController.new(project: project) # # controller.push_changes(file_path) # Remember that the path is changed # controller.update_priority(open: file_path) # Remember that an editor opens the path # controller.make_request(...) # Make an instance of TypeCheckRequest that contains list of all paths to type check # ``` class TypeCheckController attr_reader project: Project attr_reader priority_paths: Set[Pathname] attr_reader changed_paths: Set[Pathname] attr_reader target_paths: Array[TargetPaths] # TargetPaths object keeps track of the expanded absolute paths of each target # # 1. *Library path* is a RBS file that is loaded as a part of a library # 2. *Signature path* is a RBS file that is loaded as a part of the application library # 3. *Code path* is a Ruby file that is being type checked # class TargetPaths attr_reader project: Project attr_reader target: Project::Target # Set of absolute paths of Ruby code # attr_reader code_paths: Set[Pathname] # Set of absolute paths of app signatures # attr_reader signature_paths: Set[Pathname] # Set of absolute paths of library signatures # # Unlike `code_paths` and `signature_paths`, the `library_paths` must be added explicitly not by `#add` method. # attr_reader library_paths: Set[Pathname] def initialize: (project: Project, target: Project::Target) -> void def all_paths: () -> Set[Pathname] def library_path?: (Pathname path) -> bool def signature_path?: (Pathname path) -> bool def code_path?: (Pathname path) -> bool # Adds `path` to the object # # Returns `false` if the path is not a part of the project. # # Whether `path` is a code path or signature path is automatically detected. # `library: true` is required to add the path to library path. # def add: (Pathname path, ?library: bool) -> bool alias << add end def initialize: (project: Project) -> void def load: (command_line_args: Array[String]) -> void def push_changes: (Pathname path) -> void def update_priority: (open: Pathname) -> void | (close: Pathname) -> void def make_request: (?guid: String, ?last_request: TypeCheckRequest?, ?include_unchanged: bool) -> TypeCheckRequest? end type lsp_notification = { method: String, params: untyped } type lsp_request = { id: String, method: String, params: untyped } type lsp_response = { id: String, result: untyped } type lsp_message = { method: String, id: String?, params: untyped?, result: untyped? } class ResultHandler attr_reader request: lsp_request attr_reader completion_handler: (^(lsp_response) -> void)? attr_reader response: lsp_response? @completed: bool def initialize: (request: untyped) -> void def process_response: (lsp_response message) -> bool def result: () -> untyped def completed?: () -> bool def on_completion: () ?{ (lsp_response) -> void } -> void end class GroupHandler attr_reader request: lsp_request attr_reader handlers: Hash[String, ResultHandler] attr_reader completion_handler: (^(Array[ResultHandler]) -> void)? def initialize: () -> void def process_response: (lsp_response message) -> bool def completed?: () -> bool def <<: (ResultHandler handler) -> void def on_completion: () { (Array[ResultHandler]) -> void } -> void end class ResultController attr_reader handlers: Array[ResultHandler | GroupHandler] def initialize: () -> void def <<: (ResultHandler | GroupHandler handler) -> void def request_group: () { (GroupHandler) -> void } -> GroupHandler def process_response: (lsp_response message) -> bool end module MessageUtils : _WithMessage interface _WithMessage def message: () -> untyped end def request?: () -> bool def notification?: () -> bool def response?: () -> bool %a{pure} def method: () -> String? %a{pure} def id: () -> String? %a{pure} def result: () -> untyped? %a{pure} def params: () -> untyped? end class ReceiveMessageJob attr_reader source: WorkerProcess | :client attr_reader message: untyped def initialize: (source: WorkerProcess | :client, message: untyped) -> void include MessageUtils end class SendMessageJob attr_reader dest: WorkerProcess | :client attr_reader message: untyped def initialize: (dest: WorkerProcess | :client, message: untyped) -> void def self.to_worker: (WorkerProcess, message: untyped) -> SendMessageJob def self.to_client: (message: untyped) -> SendMessageJob include MessageUtils end attr_reader project: Project attr_reader reader: LanguageServer::Protocol::Transport::Io::Reader attr_reader writer: LanguageServer::Protocol::Transport::Io::Writer attr_reader commandline_args: Array[String] attr_reader interaction_worker: WorkerProcess? attr_reader typecheck_workers: Array[WorkerProcess] attr_reader job_queue: Thread::Queue attr_reader current_type_check_request: TypeCheckRequest? attr_reader controller: TypeCheckController attr_reader result_controller: ResultController attr_reader initialize_params: untyped attr_accessor typecheck_automatically: bool attr_reader start_type_checking_queue: DelayQueue def initialize: (project: Project, reader: untyped, writer: untyped, interaction_worker: WorkerProcess?, typecheck_workers: Array[WorkerProcess], ?queue: Thread::Queue) -> void # Start the Steep language server # # Returns after the language server shutdown. # The shutdown process starts by `exit` message. # # Raises an exception if the worker processes doesn't shutdown properly, like being `#kill`-ed. # Exiting the process is assumed in the case of error. # The only one cleanup it does is stopping the worker processes, by `SIGKILL`. # def start: () -> void # Stops the language server workers by sending SIGTERM # # This skips the normal shutdown process defined in LSP. # The `#start` call will result in an exception. # def kill: () -> void def each_worker: () { (WorkerProcess) -> void } -> void | () -> Enumerator[WorkerProcess, void] def pathname: (String uri) -> Pathname? def work_done_progress_supported?: () -> bool def file_system_watcher_supported?: () -> bool def process_message_from_client: (untyped message) -> void def process_message_from_worker: (untyped message, worker: WorkerProcess) -> void def start_type_check: (TypeCheckRequest request, last_request: TypeCheckRequest?, start_progress: bool) -> void def on_type_check_update: (guid: String, path: Pathname) -> void def broadcast_notification: (lsp_notification message) -> void def send_notification: (lsp_notification message, worker: WorkerProcess) -> void def fresh_request_id: () -> String def send_request: (method: String, worker: WorkerProcess, ?id: String, ?params: untyped?) ?{ (ResultHandler) -> void } -> ResultHandler def group_request: () { (GroupHandler) -> void } -> GroupHandler end end end