├── rustfmt.toml ├── .gitignore ├── tests └── dummy.rs ├── .travis.yml ├── .project ├── README.md ├── src ├── lib.rs ├── lsp_transport.rs ├── server_tests.rs └── lsp.rs ├── Cargo.toml └── LICENSE /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width=120 2 | hard_tabs=true 3 | normalise_comments=false 4 | wrap_comments=false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | /Cargo.lock 3 | /subcrates/melnorme*/Cargo.lock 4 | # Ignore Eclipse settings: 5 | .settings/ -------------------------------------------------------------------------------- /tests/dummy.rs: -------------------------------------------------------------------------------- 1 | // Blank file, workaround to make `cargo test` build all targets, see: 2 | // https://github.com/rust-lang/cargo/issues/2495#issuecomment-235114484 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | # - 1.10.0 5 | # - stable 6 | # - beta 7 | - nightly 8 | 9 | matrix: 10 | allow_failures: 11 | - rust: nightly 12 | 13 | script: 14 | - cargo build --verbose 15 | - cargo test --verbose 16 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | RustLSP 4 | 5 | 6 | 7 | 8 | 9 | com.github.rustdt.ide.core.Builder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | 16 | com.github.rustdt.ide.core.nature 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/RustDT/RustLSP.svg?branch=master)](https://travis-ci.org/RustDT/RustLSP) 2 | 3 | # RustLSP 4 | A library for working with the Language Server Protocol, as either client or server. 5 | (LSP protocol only, not tied to any particular language engine) 6 | 7 | ## Examples: 8 | 9 | See full server/client example here: 10 | [src/server_tests.rs](src/server_tests.rs) 11 | 12 | ### Projects using RustLSP: 13 | * [MockLS](https://github.com/RustDT/MockLS) 14 | * [RLS](https://github.com/jonathandturner/rls/pull/96) (in PR only) 15 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | 4 | ### RustLSP 5 | 6 | # Examples: 7 | 8 | See full server/client example here: 9 | https://github.com/RustDT/RustLSP/blob/master/src/server_tests.rs 10 | 11 | */ 12 | 13 | 14 | #![allow(non_snake_case)] 15 | #![allow(non_camel_case_types)] 16 | #![allow(non_upper_case_globals)] 17 | 18 | extern crate serde_json; 19 | extern crate serde; 20 | 21 | pub extern crate rustdt_util as util; 22 | pub extern crate jsonrpc; 23 | pub extern crate languageserver_types as ls_types; 24 | 25 | #[macro_use] extern crate log; 26 | 27 | pub mod lsp_transport; 28 | pub mod lsp; 29 | 30 | #[cfg(test)] 31 | mod server_tests; -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust_lsp" 3 | version = "0.6.0" 4 | authors = ["Bruno Medeiros "] 5 | 6 | description = "A library for working with the Language Server Protocol, as either client or server." 7 | repository = "https://github.com/RustDT/rustlsp" 8 | documentation = "https://docs.rs/rustlsp" 9 | license = "Apache-2.0" 10 | keywords = ["rustlsp", "lsp"] 11 | 12 | 13 | [build-dependencies] 14 | serde_codegen = { version = "0.8", optional = true } 15 | 16 | [dependencies] 17 | rustdt_util = "0.2.3" 18 | rustdt-json_rpc = "0.3.0" 19 | log = "0.3.6" 20 | serde = "0.8" 21 | serde_json = "0.8" 22 | languageserver-types = { version = "0.6.0" } 23 | 24 | 25 | [lib] 26 | name = "rust_lsp" 27 | path = "src/lib.rs" 28 | -------------------------------------------------------------------------------- /src/lsp_transport.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Bruno Medeiros 2 | // 3 | // Licensed under the Apache License, Version 2.0 4 | // . 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | 9 | use std::io::{self, Read}; 10 | 11 | use util::core::*; 12 | 13 | use jsonrpc::service_util::MessageReader; 14 | use jsonrpc::service_util::MessageWriter; 15 | 16 | /* ----------------- ----------------- */ 17 | 18 | pub struct LSPMessageReader(pub T); 19 | 20 | impl MessageReader for LSPMessageReader { 21 | fn read_next(&mut self) -> GResult { 22 | parse_transport_message(&mut self.0) 23 | } 24 | } 25 | 26 | pub struct LSPMessageWriter(pub T); 27 | 28 | impl MessageWriter for LSPMessageWriter { 29 | fn write_message(&mut self, msg: &str) -> Result<(), GError> { 30 | write_transport_message(msg, &mut self.0) 31 | } 32 | } 33 | 34 | /* ----------------- Parse content-length ----------------- */ 35 | 36 | const CONTENT_LENGTH: &'static str = "Content-Length:"; 37 | 38 | pub fn parse_transport_message(reader: &mut R) -> GResult 39 | { 40 | 41 | let mut content_length : u32 = 0; 42 | 43 | loop { 44 | let mut line = String::new(); 45 | 46 | try!(reader.read_line(&mut line)); 47 | 48 | if line.starts_with(CONTENT_LENGTH) { 49 | let len_str : &str = &line[CONTENT_LENGTH.len()..]; 50 | let int_result = len_str.trim().parse::(); 51 | 52 | content_length = try!(int_result); 53 | 54 | } else if line.eq("\r\n") { 55 | break; 56 | } else if line.is_empty() { 57 | return Err("End of stream reached.".into()); 58 | } 59 | } 60 | if content_length == 0 { 61 | return Err((String::from(CONTENT_LENGTH) + " not defined or invalid.").into()); 62 | } 63 | 64 | let mut message_reader = reader.take(content_length as u64); 65 | let mut message = String::new(); 66 | try!(message_reader.read_to_string(&mut message)); 67 | return Ok(message); 68 | } 69 | 70 | 71 | #[test] 72 | fn parse_transport_message__test() { 73 | use std::io::BufReader; 74 | 75 | let string = "Content-Length: 10 \r\n\r\n1234567890abcdef"; 76 | assert_eq!(parse_transport_message(&mut BufReader::new(string.as_bytes())).unwrap(), "1234567890"); 77 | 78 | // Allow other header fields 79 | let string = "Content-Length: 13 \r\nContent-Blah\r\n\r\n1234\n567\r\n890abcdef"; 80 | assert_eq!(parse_transport_message(&mut BufReader::new(string.as_bytes())).unwrap(), "1234\n567\r\n890"); 81 | 82 | // Test no-content 83 | let string = "\r\n\r\n1234567890abcdef"; 84 | let err : GError = parse_transport_message(&mut BufReader::new(string.as_bytes())).unwrap_err(); 85 | assert_eq!(&err.to_string(), "Content-Length: not defined or invalid."); 86 | 87 | // Test EOS 88 | let string = ""; 89 | let err : GError = parse_transport_message(&mut BufReader::new(string.as_bytes())).unwrap_err(); 90 | assert_eq!(&err.to_string(), "End of stream reached."); 91 | 92 | } 93 | 94 | pub fn write_transport_message(message: & str, out: &mut WRITE) -> GResult<()> 95 | { 96 | // let out : &mut io::Write = out; 97 | try!(out.write_all(CONTENT_LENGTH.as_bytes())); 98 | try!(out.write(&[' ' as u8])); 99 | let contents = message.as_bytes(); 100 | try!(out.write_all(contents.len().to_string().as_bytes())); 101 | try!(out.write_all("\r\n\r\n".as_bytes())); 102 | try!(out.write_all(message.as_bytes())); 103 | try!(out.flush()); 104 | Ok(()) 105 | } 106 | 107 | 108 | #[test] 109 | fn write_transport_message__test() { 110 | use util::tests::*; 111 | 112 | let mut out : Vec = vec!['x' as u8]; 113 | write_transport_message(&"1234\n67", &mut out).unwrap(); 114 | 115 | assert_equal(String::from_utf8(out).unwrap(), "xContent-Length: 7\r\n\r\n1234\n67".to_string()); 116 | } -------------------------------------------------------------------------------- /src/server_tests.rs: -------------------------------------------------------------------------------- 1 | /* ----------------- Tests ----------------- */ 2 | 3 | 4 | use lsp::*; 5 | use jsonrpc::method_types::MethodError; 6 | use jsonrpc::*; 7 | use ls_types::*; 8 | 9 | use jsonrpc::json_util::JsonObject; 10 | use serde_json::Value; 11 | 12 | use std::io; 13 | use std::thread; 14 | use std::net::TcpListener; 15 | use std::net::TcpStream; 16 | 17 | 18 | #[test] 19 | pub fn test_run_lsp_server() { 20 | 21 | let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap(); 22 | let local_addr = listener.local_addr().unwrap(); 23 | 24 | let server_listener = thread::spawn(|| { 25 | tcp_server(listener) 26 | }); 27 | 28 | let stream = TcpStream::connect(local_addr).unwrap(); 29 | let out_stream = stream.try_clone().expect("Failed to clone stream"); 30 | let mut endpoint = LSPEndpoint::create_lsp_output_with_output_stream(|| { out_stream }); 31 | 32 | let ls_client = TestsLanguageClient { counter: 0, endpoint : endpoint.clone() }; 33 | 34 | let client_handler = thread::spawn(|| { 35 | let mut input = io::BufReader::new(stream); 36 | let endpoint = ls_client.endpoint.clone(); 37 | LSPEndpoint::run_client_from_input(&mut input, endpoint, ls_client); 38 | }); 39 | 40 | let init_params = InitializeParams { 41 | process_id: None, 42 | root_path: None, 43 | initialization_options: None, 44 | capabilities: Value::Object(JsonObject::new()), 45 | }; 46 | 47 | // Create an rpc handle to the server methods 48 | let mut server_handle = server_rpc_handle(&mut endpoint); 49 | 50 | server_handle.initialize(init_params).unwrap(); 51 | 52 | server_handle.shutdown().unwrap(); 53 | 54 | server_handle.exit().unwrap(); 55 | 56 | client_handler.join().unwrap(); 57 | server_listener.join().unwrap(); 58 | } 59 | 60 | fn tcp_server(listener: TcpListener) { 61 | 62 | for stream in listener.incoming() { 63 | let stream = stream.expect("Failed to open incoming stream"); 64 | let conn_handler = thread::spawn(move|| { 65 | handle_connection(stream) 66 | }); 67 | 68 | // Only listen to first connection, so that this example can be run as a test 69 | conn_handler.join().unwrap(); 70 | break; 71 | } 72 | 73 | drop(listener); 74 | } 75 | 76 | fn handle_connection(stream: TcpStream) { 77 | let out_stream = stream.try_clone().expect("Failed to clone stream"); 78 | let endpoint = LSPEndpoint::create_lsp_output_with_output_stream(|| { out_stream }); 79 | 80 | let ls = TestsLanguageServer { counter : 0, endpoint : endpoint.clone() }; 81 | 82 | let mut input = io::BufReader::new(stream); 83 | LSPEndpoint::run_server_from_input(&mut input, endpoint, ls); 84 | } 85 | 86 | pub struct TestsLanguageServer { 87 | counter: u32, 88 | endpoint: Endpoint, 89 | } 90 | 91 | impl TestsLanguageServer { 92 | 93 | pub fn error_not_available(data : DATA) -> MethodError { 94 | let msg = "Functionality not implemented.".to_string(); 95 | MethodError:: { code : 1, message : msg, data : data } 96 | } 97 | 98 | } 99 | 100 | impl LanguageServerHandling for TestsLanguageServer { 101 | 102 | fn initialize(&mut self, _: InitializeParams, completable: MethodCompletable) { 103 | let capabilities = ServerCapabilities::default(); 104 | assert_eq!(self.counter, 0); 105 | self.counter = 1; 106 | completable.complete(Ok(InitializeResult { capabilities : capabilities })) 107 | } 108 | fn shutdown(&mut self, _: (), completable: LSCompletable<()>) { 109 | completable.complete(Ok(())); 110 | } 111 | fn exit(&mut self, _: ()) { 112 | self.endpoint.request_shutdown(); 113 | } 114 | 115 | fn workspace_change_configuration(&mut self, _: DidChangeConfigurationParams) {} 116 | fn did_open_text_document(&mut self, _: DidOpenTextDocumentParams) {} 117 | fn did_change_text_document(&mut self, _: DidChangeTextDocumentParams) {} 118 | fn did_close_text_document(&mut self, _: DidCloseTextDocumentParams) {} 119 | fn did_save_text_document(&mut self, _: DidSaveTextDocumentParams) {} 120 | fn did_change_watched_files(&mut self, _: DidChangeWatchedFilesParams) {} 121 | 122 | fn completion(&mut self, _: TextDocumentPositionParams, completable: LSCompletable) { 123 | completable.complete(Err(Self::error_not_available(()))); 124 | } 125 | fn resolve_completion_item(&mut self, _: CompletionItem, completable: LSCompletable) { 126 | completable.complete(Err(Self::error_not_available(()))); 127 | } 128 | fn hover(&mut self, _: TextDocumentPositionParams, completable: LSCompletable) { 129 | let mut endpoint = self.endpoint.clone(); 130 | thread::spawn(move || { 131 | client_rpc_handle(&mut endpoint).telemetry_event(Value::Null) 132 | .unwrap(); 133 | 134 | let hover_str = "hover_text".to_string(); 135 | let hover = Hover { contents: vec![MarkedString::String(hover_str)], range: None }; 136 | 137 | completable.complete(Ok(hover)); 138 | }); 139 | } 140 | fn signature_help(&mut self, _: TextDocumentPositionParams, completable: LSCompletable) { 141 | completable.complete(Err(Self::error_not_available(()))); 142 | } 143 | fn goto_definition(&mut self, _: TextDocumentPositionParams, completable: LSCompletable>) { 144 | completable.complete(Err(Self::error_not_available(()))); 145 | } 146 | fn references(&mut self, _: ReferenceParams, completable: LSCompletable>) { 147 | completable.complete(Err(Self::error_not_available(()))); 148 | } 149 | fn document_highlight(&mut self, _: TextDocumentPositionParams, completable: LSCompletable>) { 150 | completable.complete(Err(Self::error_not_available(()))); 151 | } 152 | fn document_symbols(&mut self, _: DocumentSymbolParams, completable: LSCompletable>) { 153 | completable.complete(Err(Self::error_not_available(()))); 154 | } 155 | fn workspace_symbols(&mut self, _: WorkspaceSymbolParams, completable: LSCompletable>) { 156 | completable.complete(Err(Self::error_not_available(()))); 157 | } 158 | fn code_action(&mut self, _: CodeActionParams, completable: LSCompletable>) { 159 | completable.complete(Err(Self::error_not_available(()))); 160 | } 161 | fn code_lens(&mut self, _: CodeLensParams, completable: LSCompletable>) { 162 | completable.complete(Err(Self::error_not_available(()))); 163 | } 164 | fn code_lens_resolve(&mut self, _: CodeLens, completable: LSCompletable) { 165 | completable.complete(Err(Self::error_not_available(()))); 166 | } 167 | fn document_link(&mut self, _params: DocumentLinkParams, completable: LSCompletable>) { 168 | completable.complete(Err(Self::error_not_available(()))); 169 | } 170 | fn document_link_resolve(&mut self, _params: DocumentLink, completable: LSCompletable) { 171 | completable.complete(Err(Self::error_not_available(()))); 172 | } 173 | fn formatting(&mut self, _: DocumentFormattingParams, completable: LSCompletable>) { 174 | completable.complete(Err(Self::error_not_available(()))); 175 | } 176 | fn range_formatting(&mut self, _: DocumentRangeFormattingParams, completable: LSCompletable>) { 177 | completable.complete(Err(Self::error_not_available(()))); 178 | } 179 | fn on_type_formatting(&mut self, _: DocumentOnTypeFormattingParams, completable: LSCompletable>) { 180 | completable.complete(Err(Self::error_not_available(()))); 181 | } 182 | fn rename(&mut self, _: RenameParams, completable: LSCompletable) { 183 | completable.complete(Err(Self::error_not_available(()))); 184 | } 185 | } 186 | 187 | /* ----------------- ----------------- */ 188 | 189 | pub struct TestsLanguageClient { 190 | counter: u32, 191 | endpoint: Endpoint, 192 | } 193 | 194 | #[allow(unused_variables)] 195 | impl LanguageClientHandling for TestsLanguageClient { 196 | 197 | fn show_message(&mut self, params: ShowMessageParams) { 198 | 199 | } 200 | 201 | fn show_message_request( 202 | &mut self, params: ShowMessageRequestParams, completable: LSCompletable 203 | ) { 204 | unimplemented!(); 205 | } 206 | 207 | fn log_message(&mut self, params: LogMessageParams) { 208 | 209 | } 210 | 211 | fn telemetry_event(&mut self, params: Value) { 212 | self.counter += 1; 213 | } 214 | 215 | fn publish_diagnostics(&mut self, params: PublishDiagnosticsParams) { 216 | 217 | } 218 | 219 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/lsp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Bruno Medeiros 2 | // 3 | // Licensed under the Apache License, Version 2.0 4 | // . 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | 9 | use std::io; 10 | 11 | use util::core::*; 12 | 13 | use jsonrpc::*; 14 | pub use jsonrpc::service_util::MessageReader; 15 | pub use jsonrpc::service_util::MessageWriter; 16 | 17 | use jsonrpc::output_agent::OutputAgent; 18 | 19 | use jsonrpc::method_types::MethodError; 20 | use jsonrpc::jsonrpc_request::RequestParams; 21 | 22 | use lsp_transport::LSPMessageWriter; 23 | use lsp_transport::LSPMessageReader; 24 | use ls_types::*; 25 | use serde_json::Value; 26 | 27 | /* ----------------- ----------------- */ 28 | 29 | /// Helper empty type to help create a JSON-RPC endpoint for LSP communication 30 | pub struct LSPEndpoint { 31 | 32 | } 33 | 34 | impl LSPEndpoint { 35 | 36 | /// Create an Endpoint for use in the Language Server Protocol, 37 | /// with given output stream provider. 38 | pub fn create_lsp_output_with_output_stream(output_stream_provider: OUT_PROV) 39 | -> Endpoint 40 | where 41 | OUT : io::Write + 'static, 42 | OUT_PROV : FnOnce() -> OUT + Send + 'static 43 | { 44 | Self::create_lsp_output(|| { 45 | LSPMessageWriter(output_stream_provider()) 46 | }) 47 | } 48 | 49 | /// Create an Endpoint for use in the Language Server Protocol 50 | /// with given message writer provider. 51 | pub fn create_lsp_output(msg_writer_provider: MW_PROV) 52 | -> Endpoint 53 | where 54 | MW : MessageWriter + 'static, 55 | MW_PROV : FnOnce() -> MW + Send + 'static 56 | { 57 | let output_agent = OutputAgent::start_with_provider(msg_writer_provider); 58 | Endpoint::start_with(output_agent) 59 | } 60 | 61 | /* ----------------- ----------------- */ 62 | 63 | pub fn run_server_from_input( 64 | input: &mut io::BufRead, endpoint: Endpoint, lsp_server_handler: SERVER, 65 | ) 66 | where 67 | SERVER : LanguageServerHandling + 'static, 68 | { 69 | Self::run_server(&mut LSPMessageReader(input), endpoint, lsp_server_handler) 70 | } 71 | 72 | /// Run the message read loop on the server, for given msg_reader. 73 | /// msg_reader must be a LSPMessageReader or compatible. 74 | pub fn run_server( 75 | mut msg_reader: &mut MR, endpoint: Endpoint, lsp_server_handler: SERVER 76 | ) 77 | where 78 | SERVER : LanguageServerHandling + 'static, 79 | MR : MessageReader, 80 | { 81 | Self::run_endpoint_loop(msg_reader, endpoint, new(ServerRequestHandler(lsp_server_handler))) 82 | } 83 | 84 | pub fn run_client_from_input( 85 | input: &mut io::BufRead, endpoint: Endpoint, lsp_client_handler: CLIENT, 86 | ) 87 | where 88 | CLIENT : LanguageClientHandling + 'static, 89 | { 90 | let cl_handler = new(ClientRequestHandler(lsp_client_handler)); 91 | Self::run_endpoint_loop(&mut LSPMessageReader(input), endpoint, cl_handler) 92 | } 93 | 94 | pub fn run_endpoint_loop( 95 | mut msg_reader: &mut MR, endpoint: Endpoint, request_handler: Box 96 | ) 97 | where 98 | MR : MessageReader, 99 | { 100 | info!("Starting LSP Endpoint"); 101 | 102 | let endpoint = EndpointHandler::create(endpoint, request_handler); 103 | 104 | let result = endpoint.run_message_read_loop(msg_reader); 105 | 106 | if let Err(error) = result { 107 | error!("Error handling the incoming stream: {}", error); 108 | } 109 | } 110 | 111 | } 112 | 113 | pub type LSResult = Result>; 114 | pub type LSCompletable = MethodCompletable; 115 | 116 | /// Trait for the handling of LSP server requests 117 | pub trait LanguageServerHandling { 118 | 119 | fn initialize(&mut self, params: InitializeParams, completable: MethodCompletable); 120 | fn shutdown(&mut self, params: (), completable: LSCompletable<()>); 121 | fn exit(&mut self, params: ()); 122 | fn workspace_change_configuration(&mut self, params: DidChangeConfigurationParams); 123 | fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams); 124 | fn did_change_text_document(&mut self, params: DidChangeTextDocumentParams); 125 | fn did_close_text_document(&mut self, params: DidCloseTextDocumentParams); 126 | fn did_save_text_document(&mut self, params: DidSaveTextDocumentParams); 127 | fn did_change_watched_files(&mut self, params: DidChangeWatchedFilesParams); 128 | 129 | fn completion(&mut self, params: TextDocumentPositionParams, completable: LSCompletable); 130 | fn resolve_completion_item(&mut self, params: CompletionItem, completable: LSCompletable); 131 | fn hover(&mut self, params: TextDocumentPositionParams, completable: LSCompletable); 132 | fn signature_help(&mut self, params: TextDocumentPositionParams, completable: LSCompletable); 133 | fn goto_definition(&mut self, params: TextDocumentPositionParams, completable: LSCompletable>); 134 | fn references(&mut self, params: ReferenceParams, completable: LSCompletable>); 135 | fn document_highlight(&mut self, params: TextDocumentPositionParams, completable: LSCompletable>); 136 | fn document_symbols(&mut self, params: DocumentSymbolParams, completable: LSCompletable>); 137 | fn workspace_symbols(&mut self, params: WorkspaceSymbolParams, completable: LSCompletable>); 138 | fn code_action(&mut self, params: CodeActionParams, completable: LSCompletable>); 139 | fn code_lens(&mut self, params: CodeLensParams, completable: LSCompletable>); 140 | fn code_lens_resolve(&mut self, params: CodeLens, completable: LSCompletable); 141 | fn document_link(&mut self, params: DocumentLinkParams, completable: LSCompletable>); 142 | fn document_link_resolve(&mut self, params: DocumentLink, completable: LSCompletable); 143 | fn formatting(&mut self, params: DocumentFormattingParams, completable: LSCompletable>); 144 | fn range_formatting(&mut self, params: DocumentRangeFormattingParams, completable: LSCompletable>); 145 | fn on_type_formatting(&mut self, params: DocumentOnTypeFormattingParams, completable: LSCompletable>); 146 | fn rename(&mut self, params: RenameParams, completable: LSCompletable); 147 | 148 | #[allow(unused_variables)] 149 | fn handle_other_method(&mut self, method_name: &str, params: RequestParams, completable: ResponseCompletable) { 150 | completable.complete_with_error(jsonrpc_common::error_JSON_RPC_MethodNotFound()); 151 | } 152 | } 153 | 154 | 155 | pub struct ServerRequestHandler(pub LS); 156 | 157 | impl RequestHandler for ServerRequestHandler { 158 | 159 | fn handle_request( 160 | &mut self, method_name: &str, params: RequestParams, completable: ResponseCompletable 161 | ) { 162 | match method_name { 163 | REQUEST__Initialize => { 164 | completable.handle_request_with(params, 165 | |params, completable| self.0.initialize(params, completable) 166 | ) 167 | } 168 | REQUEST__Shutdown => { 169 | completable.handle_request_with(params, 170 | |params, completable| self.0.shutdown(params, completable) 171 | ) 172 | } 173 | NOTIFICATION__Exit => { 174 | completable.handle_notification_with(params, 175 | |params| self.0.exit(params)) 176 | } 177 | NOTIFICATION__WorkspaceChangeConfiguration => { 178 | completable.handle_notification_with(params, 179 | |params| self.0.workspace_change_configuration(params) 180 | ) 181 | } 182 | NOTIFICATION__DidOpenTextDocument => { 183 | completable.handle_notification_with(params, 184 | |params| self.0.did_open_text_document(params) 185 | ) 186 | } 187 | NOTIFICATION__DidChangeTextDocument => { 188 | completable.handle_notification_with(params, 189 | |params| self.0.did_change_text_document(params) 190 | ) 191 | } 192 | NOTIFICATION__DidCloseTextDocument => { 193 | completable.handle_notification_with(params, 194 | |params| self.0.did_close_text_document(params) 195 | ) 196 | } 197 | NOTIFICATION__DidSaveTextDocument => { 198 | completable.handle_notification_with(params, 199 | |params| self.0.did_save_text_document(params) 200 | ) 201 | } 202 | NOTIFICATION__DidChangeWatchedFiles => { 203 | completable.handle_notification_with(params, 204 | |params| self.0.did_change_watched_files(params)) 205 | } 206 | REQUEST__Completion => { 207 | completable.handle_request_with(params, 208 | |params, completable| self.0.completion(params, completable) 209 | ) 210 | } 211 | REQUEST__ResolveCompletionItem => { 212 | completable.handle_request_with(params, 213 | |params, completable| self.0.resolve_completion_item(params, completable) 214 | ) 215 | } 216 | REQUEST__Hover => { 217 | completable.handle_request_with(params, 218 | |params, completable| self.0.hover(params, completable) 219 | ) 220 | } 221 | REQUEST__SignatureHelp => { 222 | completable.handle_request_with(params, 223 | |params, completable| self.0.signature_help(params, completable) 224 | ) 225 | } 226 | REQUEST__GotoDefinition => { 227 | completable.handle_request_with(params, 228 | |params, completable| self.0.goto_definition(params, completable) 229 | ) 230 | } 231 | REQUEST__References => { 232 | completable.handle_request_with(params, 233 | |params, completable| self.0.references(params, completable) 234 | ) 235 | } 236 | REQUEST__DocumentHighlight => { 237 | completable.handle_request_with(params, 238 | |params, completable| self.0.document_highlight(params, completable) 239 | ) 240 | } 241 | REQUEST__DocumentSymbols => { 242 | completable.handle_request_with(params, 243 | |params, completable| self.0.document_symbols(params, completable) 244 | ) 245 | } 246 | REQUEST__WorkspaceSymbols => { 247 | completable.handle_request_with(params, 248 | |params, completable| self.0.workspace_symbols(params, completable) 249 | ) 250 | } 251 | REQUEST__CodeAction => { 252 | completable.handle_request_with(params, 253 | |params, completable| self.0.code_action(params, completable) 254 | ) 255 | } 256 | REQUEST__CodeLens => { 257 | completable.handle_request_with(params, 258 | |params, completable| self.0.code_lens(params, completable) 259 | ) 260 | } 261 | REQUEST__CodeLensResolve => { 262 | completable.handle_request_with(params, 263 | |params, completable| self.0.code_lens_resolve(params, completable) 264 | ) 265 | } 266 | REQUEST__DocumentLink => { 267 | completable.handle_request_with(params, 268 | |params, completable| self.0.document_link(params, completable) 269 | ) 270 | } 271 | REQUEST__DocumentLinkResolve => { 272 | completable.handle_request_with(params, 273 | |params, completable| self.0.document_link_resolve(params, completable) 274 | ) 275 | } 276 | REQUEST__Formatting => { 277 | completable.handle_request_with(params, 278 | |params, completable| self.0.formatting(params, completable) 279 | ) 280 | } 281 | REQUEST__RangeFormatting => { 282 | completable.handle_request_with(params, 283 | |params, completable| self.0.range_formatting(params, completable) 284 | ) 285 | } 286 | REQUEST__OnTypeFormatting => { 287 | completable.handle_request_with(params, 288 | |params, completable| self.0.on_type_formatting(params, completable) 289 | ) 290 | } 291 | REQUEST__Rename => { 292 | completable.handle_request_with(params, 293 | |params, completable| self.0.rename(params, completable) 294 | ) 295 | } 296 | _ => { 297 | self.0.handle_other_method(method_name, params, completable); 298 | } 299 | }; 300 | 301 | } 302 | 303 | } 304 | 305 | 306 | pub trait LspClientRpc { 307 | 308 | fn show_message(&mut self, params: ShowMessageParams) 309 | -> GResult<()>; 310 | 311 | fn show_message_request(&mut self, params: ShowMessageRequestParams) 312 | -> GResult>; 313 | 314 | fn log_message(&mut self, params: LogMessageParams) 315 | -> GResult<()>; 316 | 317 | fn telemetry_event(&mut self, params: Value) 318 | -> GResult<()>; 319 | 320 | fn publish_diagnostics(&mut self, params: PublishDiagnosticsParams) 321 | -> GResult<()>; 322 | 323 | } 324 | 325 | pub struct LspClientRpc_<'a> { 326 | pub endpoint: &'a mut Endpoint, 327 | } 328 | 329 | pub fn client_rpc_handle(endpoint : &mut Endpoint) -> LspClientRpc_ { 330 | LspClientRpc_ { endpoint: endpoint } 331 | } 332 | 333 | impl<'a> LspClientRpc for LspClientRpc_<'a> { 334 | 335 | fn show_message(&mut self, params: ShowMessageParams) 336 | -> GResult<()> 337 | { 338 | self.endpoint.send_notification(NOTIFICATION__ShowMessage, params) 339 | } 340 | 341 | fn show_message_request(&mut self, params: ShowMessageRequestParams) 342 | -> GResult> 343 | { 344 | self.endpoint.send_request(REQUEST__ShowMessageRequest, params) 345 | } 346 | 347 | fn log_message(&mut self, params: LogMessageParams) 348 | -> GResult<()> 349 | { 350 | self.endpoint.send_notification(NOTIFICATION__LogMessage, params) 351 | } 352 | 353 | fn telemetry_event(&mut self, params: Value) 354 | -> GResult<()> 355 | { 356 | self.endpoint.send_notification(NOTIFICATION__TelemetryEvent, params) 357 | } 358 | 359 | fn publish_diagnostics(&mut self, params: PublishDiagnosticsParams) 360 | -> GResult<()> 361 | { 362 | self.endpoint.send_notification(NOTIFICATION__PublishDiagnostics, params) 363 | } 364 | 365 | } 366 | 367 | /* ----------------- LSP Client: ----------------- */ 368 | 369 | pub trait LSPServerRpc { 370 | 371 | fn initialize(&mut self, params: InitializeParams) 372 | -> GResult>; 373 | 374 | fn shutdown(&mut self) 375 | -> GResult>; 376 | 377 | fn exit(&mut self) 378 | -> GResult<()>; 379 | 380 | fn workspace_change_configuration(&mut self, params: DidChangeConfigurationParams) 381 | -> GResult<()>; 382 | 383 | fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams) 384 | -> GResult<()>; 385 | 386 | fn did_change_text_document(&mut self, params: DidChangeTextDocumentParams) 387 | -> GResult<()>; 388 | 389 | fn did_close_text_document(&mut self, params: DidCloseTextDocumentParams) 390 | -> GResult<()>; 391 | 392 | fn did_save_text_document(&mut self, params: DidSaveTextDocumentParams) 393 | -> GResult<()>; 394 | 395 | fn did_change_watched_files(&mut self, params: DidChangeWatchedFilesParams) 396 | -> GResult<()>; 397 | 398 | fn completion(&mut self, params: TextDocumentPositionParams) 399 | -> GResult>; 400 | 401 | fn resolve_completion_item(&mut self, params: CompletionItem) 402 | -> GResult>; 403 | 404 | fn hover(&mut self, params: TextDocumentPositionParams) 405 | -> GResult>; 406 | 407 | fn signature_help(&mut self, params: TextDocumentPositionParams) 408 | -> GResult>; 409 | 410 | fn goto_definition(&mut self, params: TextDocumentPositionParams) 411 | -> GResult, ()>>; 412 | 413 | fn references(&mut self, params: ReferenceParams) 414 | -> GResult, ()>>; 415 | 416 | fn document_highlight(&mut self, params: TextDocumentPositionParams) 417 | -> GResult, ()>>; 418 | 419 | fn document_symbols(&mut self, params: DocumentSymbolParams) 420 | -> GResult, ()>>; 421 | 422 | fn workspace_symbols(&mut self, params: WorkspaceSymbolParams) 423 | -> GResult, ()>>; 424 | 425 | fn code_action(&mut self, params: CodeActionParams) 426 | -> GResult, ()>>; 427 | 428 | fn code_lens(&mut self, params: CodeLensParams) 429 | -> GResult, ()>>; 430 | 431 | fn code_lens_resolve(&mut self, params: CodeLens) 432 | -> GResult>; 433 | 434 | fn formatting(&mut self, params: DocumentFormattingParams) 435 | -> GResult, ()>>; 436 | 437 | fn range_formatting(&mut self, params: DocumentRangeFormattingParams) 438 | -> GResult, ()>>; 439 | 440 | fn on_type_formatting(&mut self, params: DocumentOnTypeFormattingParams) 441 | -> GResult, ()>>; 442 | 443 | fn rename(&mut self, params: RenameParams) 444 | -> GResult>; 445 | 446 | } 447 | 448 | 449 | pub struct LspServerRpc_<'a> { 450 | pub endpoint: &'a mut Endpoint, 451 | } 452 | 453 | pub fn server_rpc_handle(endpoint : &mut Endpoint) -> LspServerRpc_ { 454 | LspServerRpc_ { endpoint: endpoint } 455 | } 456 | 457 | impl<'a> LSPServerRpc for LspServerRpc_<'a> { 458 | 459 | fn initialize(&mut self, params: InitializeParams) 460 | -> GResult> 461 | { 462 | self.endpoint.send_request(REQUEST__Initialize, params) 463 | } 464 | 465 | fn shutdown(&mut self) 466 | -> GResult> 467 | { 468 | self.endpoint.send_request(REQUEST__Shutdown, ()) 469 | } 470 | 471 | fn exit(&mut self) 472 | -> GResult<()> 473 | { 474 | self.endpoint.send_notification(NOTIFICATION__Exit, ()) 475 | } 476 | 477 | fn workspace_change_configuration(&mut self, params: DidChangeConfigurationParams) 478 | -> GResult<()> 479 | { 480 | self.endpoint.send_notification(NOTIFICATION__WorkspaceChangeConfiguration, params) 481 | } 482 | 483 | fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams) 484 | -> GResult<()> 485 | { 486 | self.endpoint.send_notification(NOTIFICATION__DidOpenTextDocument, params) 487 | } 488 | 489 | fn did_change_text_document(&mut self, params: DidChangeTextDocumentParams) 490 | -> GResult<()> 491 | { 492 | self.endpoint.send_notification(NOTIFICATION__DidChangeTextDocument, params) 493 | } 494 | 495 | fn did_close_text_document(&mut self, params: DidCloseTextDocumentParams) 496 | -> GResult<()> 497 | { 498 | self.endpoint.send_notification(NOTIFICATION__DidCloseTextDocument, params) 499 | } 500 | 501 | fn did_save_text_document(&mut self, params: DidSaveTextDocumentParams) 502 | -> GResult<()> 503 | { 504 | self.endpoint.send_notification(NOTIFICATION__DidSaveTextDocument, params) 505 | } 506 | 507 | fn did_change_watched_files(&mut self, params: DidChangeWatchedFilesParams) 508 | -> GResult<()> 509 | { 510 | self.endpoint.send_notification(NOTIFICATION__DidChangeWatchedFiles, params) 511 | } 512 | 513 | fn completion(&mut self, params: TextDocumentPositionParams) 514 | -> GResult> 515 | { 516 | self.endpoint.send_request(REQUEST__Completion, params) 517 | } 518 | 519 | fn resolve_completion_item(&mut self, params: CompletionItem) 520 | -> GResult> 521 | { 522 | self.endpoint.send_request(REQUEST__ResolveCompletionItem, params) 523 | } 524 | 525 | fn hover(&mut self, params: TextDocumentPositionParams) 526 | -> GResult> 527 | { 528 | self.endpoint.send_request(REQUEST__Hover, params) 529 | } 530 | 531 | fn signature_help(&mut self, params: TextDocumentPositionParams) 532 | -> GResult> 533 | { 534 | self.endpoint.send_request(REQUEST__SignatureHelp, params) 535 | } 536 | 537 | fn goto_definition(&mut self, params: TextDocumentPositionParams) 538 | -> GResult, ()>> 539 | { 540 | self.endpoint.send_request(REQUEST__GotoDefinition, params) 541 | } 542 | 543 | fn references(&mut self, params: ReferenceParams) 544 | -> GResult, ()>> 545 | { 546 | self.endpoint.send_request(REQUEST__References, params) 547 | } 548 | 549 | fn document_highlight(&mut self, params: TextDocumentPositionParams) 550 | -> GResult, ()>> 551 | { 552 | self.endpoint.send_request(REQUEST__DocumentHighlight, params) 553 | } 554 | 555 | fn document_symbols(&mut self, params: DocumentSymbolParams) 556 | -> GResult, ()>> 557 | { 558 | self.endpoint.send_request(REQUEST__DocumentSymbols, params) 559 | } 560 | 561 | fn workspace_symbols(&mut self, params: WorkspaceSymbolParams) 562 | -> GResult, ()>> 563 | { 564 | self.endpoint.send_request(REQUEST__WorkspaceSymbols, params) 565 | } 566 | 567 | fn code_action(&mut self, params: CodeActionParams) 568 | -> GResult, ()>> 569 | { 570 | self.endpoint.send_request(REQUEST__CodeAction, params) 571 | } 572 | 573 | fn code_lens(&mut self, params: CodeLensParams) 574 | -> GResult, ()>> 575 | { 576 | self.endpoint.send_request(REQUEST__CodeLens, params) 577 | } 578 | 579 | fn code_lens_resolve(&mut self, params: CodeLens) 580 | -> GResult> 581 | { 582 | self.endpoint.send_request(REQUEST__CodeLensResolve, params) 583 | } 584 | 585 | fn formatting(&mut self, params: DocumentFormattingParams) 586 | -> GResult, ()>> 587 | { 588 | self.endpoint.send_request(REQUEST__Formatting, params) 589 | } 590 | 591 | fn range_formatting(&mut self, params: DocumentRangeFormattingParams) 592 | -> GResult, ()>> 593 | { 594 | self.endpoint.send_request(REQUEST__RangeFormatting, params) 595 | } 596 | 597 | fn on_type_formatting(&mut self, params: DocumentOnTypeFormattingParams) 598 | -> GResult, ()>> 599 | { 600 | self.endpoint.send_request(REQUEST__OnTypeFormatting, params) 601 | } 602 | 603 | fn rename(&mut self, params: RenameParams) 604 | -> GResult> 605 | { 606 | self.endpoint.send_request(REQUEST__Rename, params) 607 | } 608 | 609 | } 610 | 611 | 612 | /// Trait for the handling of LSP client requests. 613 | /// (An LSP server can act as a JSON-RPC Client and request to the LSP client) 614 | pub trait LanguageClientHandling { 615 | 616 | fn show_message(&mut self, params: ShowMessageParams); 617 | 618 | fn show_message_request(&mut self, params: ShowMessageRequestParams, 619 | completable: LSCompletable); 620 | 621 | fn log_message(&mut self, params: LogMessageParams); 622 | 623 | fn telemetry_event(&mut self, params: Value); 624 | 625 | fn publish_diagnostics(&mut self, params: PublishDiagnosticsParams); 626 | 627 | #[allow(unused_variables)] 628 | fn handle_other_method(&mut self, method_name: &str, params: RequestParams, completable: ResponseCompletable) { 629 | completable.complete_with_error(jsonrpc_common::error_JSON_RPC_MethodNotFound()); 630 | } 631 | 632 | } 633 | 634 | pub struct ClientRequestHandler(pub LS); 635 | 636 | impl RequestHandler for ClientRequestHandler { 637 | 638 | fn handle_request( 639 | &mut self, method_name: &str, params: RequestParams, completable: ResponseCompletable 640 | ) { 641 | match method_name { 642 | NOTIFICATION__ShowMessage => { 643 | completable.handle_notification_with(params, 644 | |params| self.0.show_message(params)) 645 | } 646 | REQUEST__ShowMessageRequest => { 647 | completable.handle_request_with(params, 648 | |params, completable| self.0.show_message_request(params, completable) 649 | ) 650 | } 651 | NOTIFICATION__LogMessage => { 652 | completable.handle_notification_with(params, 653 | |params| self.0.log_message(params)) 654 | } 655 | NOTIFICATION__TelemetryEvent => { 656 | completable.handle_notification_with(params, 657 | |params| self.0.telemetry_event(params) 658 | ) 659 | } 660 | NOTIFICATION__PublishDiagnostics => { 661 | completable.handle_notification_with(params, 662 | |params| self.0.publish_diagnostics(params) 663 | ) 664 | } 665 | _ => { 666 | self.0.handle_other_method(method_name, params, completable); 667 | } 668 | } 669 | } 670 | 671 | } --------------------------------------------------------------------------------