jaclang 0.0.5__py3-none-any.whl → 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (94) hide show
  1. jaclang/__init__.py +2 -1
  2. jaclang/cli/__jac_gen__/__init__.py +0 -0
  3. jaclang/cli/__jac_gen__/cli.py +175 -0
  4. jaclang/cli/__jac_gen__/cmds.py +132 -0
  5. jaclang/cli/cli.jac +2 -2
  6. jaclang/cli/cmds.jac +8 -2
  7. jaclang/cli/impl/__jac_gen__/__init__.py +0 -0
  8. jaclang/cli/impl/__jac_gen__/cli_impl.py +16 -0
  9. jaclang/cli/impl/__jac_gen__/cmds_impl.py +26 -0
  10. jaclang/cli/impl/cli_impl.jac +25 -8
  11. jaclang/cli/impl/cmds_impl.jac +35 -6
  12. jaclang/core/__jac_gen__/__init__.py +0 -0
  13. jaclang/core/__jac_gen__/primitives.py +567 -0
  14. jaclang/core/impl/__jac_gen__/__init__.py +0 -0
  15. jaclang/core/impl/__jac_gen__/arch_impl.py +24 -0
  16. jaclang/core/impl/__jac_gen__/element_impl.py +26 -0
  17. jaclang/core/impl/__jac_gen__/exec_ctx_impl.py +12 -0
  18. jaclang/core/impl/__jac_gen__/memory_impl.py +14 -0
  19. jaclang/core/impl/element_impl.jac +3 -3
  20. jaclang/core/impl/exec_ctx_impl.jac +3 -6
  21. jaclang/core/primitives.jac +4 -3
  22. jaclang/jac/absyntree.py +555 -180
  23. jaclang/jac/constant.py +6 -0
  24. jaclang/jac/importer.py +34 -56
  25. jaclang/jac/langserve.py +26 -0
  26. jaclang/jac/lexer.py +35 -3
  27. jaclang/jac/parser.py +146 -115
  28. jaclang/jac/passes/blue/__init__.py +8 -3
  29. jaclang/jac/passes/blue/ast_build_pass.py +454 -305
  30. jaclang/jac/passes/blue/blue_pygen_pass.py +112 -74
  31. jaclang/jac/passes/blue/decl_def_match_pass.py +49 -277
  32. jaclang/jac/passes/blue/import_pass.py +1 -1
  33. jaclang/jac/passes/blue/pyout_pass.py +74 -0
  34. jaclang/jac/passes/blue/semantic_check_pass.py +37 -0
  35. jaclang/jac/passes/blue/sym_tab_build_pass.py +1045 -0
  36. jaclang/jac/passes/blue/tests/test_ast_build_pass.py +2 -2
  37. jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +9 -28
  38. jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +13 -22
  39. jaclang/jac/passes/blue/tests/test_sym_tab_build_pass.py +22 -0
  40. jaclang/jac/passes/ir_pass.py +8 -6
  41. jaclang/jac/passes/purple/__jac_gen__/__init__.py +0 -0
  42. jaclang/jac/passes/purple/__jac_gen__/analyze_pass.py +37 -0
  43. jaclang/jac/passes/purple/__jac_gen__/purple_pygen_pass.py +305 -0
  44. jaclang/jac/passes/purple/impl/__jac_gen__/__init__.py +0 -0
  45. jaclang/jac/passes/purple/impl/__jac_gen__/purple_pygen_pass_impl.py +23 -0
  46. jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +2 -5
  47. jaclang/jac/symtable.py +154 -0
  48. jaclang/jac/tests/fixtures/__jac_gen__/__init__.py +0 -0
  49. jaclang/jac/tests/fixtures/__jac_gen__/hello_world.py +16 -0
  50. jaclang/jac/tests/fixtures/fam.jac +7 -8
  51. jaclang/jac/tests/fixtures/mod_doc_test.jac +1 -0
  52. jaclang/jac/tests/test_parser.py +8 -0
  53. jaclang/jac/transform.py +41 -14
  54. jaclang/jac/transpiler.py +18 -9
  55. jaclang/utils/fstring_parser.py +2 -2
  56. jaclang/utils/helpers.py +41 -0
  57. jaclang/utils/lang_tools.py +12 -2
  58. jaclang/utils/test.py +41 -0
  59. jaclang/vendor/__init__.py +1 -0
  60. jaclang/vendor/pygls/__init__.py +25 -0
  61. jaclang/vendor/pygls/capabilities.py +502 -0
  62. jaclang/vendor/pygls/client.py +176 -0
  63. jaclang/vendor/pygls/constants.py +26 -0
  64. jaclang/vendor/pygls/exceptions.py +220 -0
  65. jaclang/vendor/pygls/feature_manager.py +241 -0
  66. jaclang/vendor/pygls/lsp/__init__.py +139 -0
  67. jaclang/vendor/pygls/lsp/client.py +2224 -0
  68. jaclang/vendor/pygls/lsprotocol/__init__.py +2 -0
  69. jaclang/vendor/pygls/lsprotocol/_hooks.py +1233 -0
  70. jaclang/vendor/pygls/lsprotocol/converters.py +17 -0
  71. jaclang/vendor/pygls/lsprotocol/types.py +12820 -0
  72. jaclang/vendor/pygls/lsprotocol/validators.py +47 -0
  73. jaclang/vendor/pygls/progress.py +79 -0
  74. jaclang/vendor/pygls/protocol.py +1184 -0
  75. jaclang/vendor/pygls/server.py +620 -0
  76. jaclang/vendor/pygls/uris.py +184 -0
  77. jaclang/vendor/pygls/workspace/__init__.py +81 -0
  78. jaclang/vendor/pygls/workspace/position.py +204 -0
  79. jaclang/vendor/pygls/workspace/text_document.py +234 -0
  80. jaclang/vendor/pygls/workspace/workspace.py +311 -0
  81. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/METADATA +1 -1
  82. jaclang-0.0.8.dist-info/RECORD +118 -0
  83. jaclang/core/jaclang.jac +0 -62
  84. jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +0 -53
  85. jaclang/jac/passes/blue/type_analyze_pass.py +0 -728
  86. jaclang/jac/sym_table.py +0 -127
  87. jaclang-0.0.5.dist-info/RECORD +0 -73
  88. /jaclang/{utils → vendor}/sly/__init__.py +0 -0
  89. /jaclang/{utils → vendor}/sly/docparse.py +0 -0
  90. /jaclang/{utils → vendor}/sly/lex.py +0 -0
  91. /jaclang/{utils → vendor}/sly/yacc.py +0 -0
  92. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/WHEEL +0 -0
  93. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/entry_points.txt +0 -0
  94. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1184 @@
1
+ ############################################################################
2
+ # Copyright(c) Open Law Library. All rights reserved. #
3
+ # See ThirdPartyNotices.txt in the project root for additional notices. #
4
+ # #
5
+ # Licensed under the Apache License, Version 2.0 (the "License") #
6
+ # you may not use this file except in compliance with the License. #
7
+ # You may obtain a copy of the License at #
8
+ # #
9
+ # http: // www.apache.org/licenses/LICENSE-2.0 #
10
+ # #
11
+ # Unless required by applicable law or agreed to in writing, software #
12
+ # distributed under the License is distributed on an "AS IS" BASIS, #
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14
+ # See the License for the specific language governing permissions and #
15
+ # limitations under the License. #
16
+ ############################################################################
17
+ from __future__ import annotations
18
+ import asyncio
19
+ import enum
20
+ import functools
21
+ import json
22
+ import logging
23
+ import re
24
+ import sys
25
+ import uuid
26
+ import traceback
27
+ from collections import namedtuple
28
+ from concurrent.futures import Future
29
+ from functools import lru_cache, partial
30
+ from itertools import zip_longest
31
+ from typing import (
32
+ Any,
33
+ Callable,
34
+ Dict,
35
+ List,
36
+ Optional,
37
+ Type,
38
+ TypeVar,
39
+ Union,
40
+ TYPE_CHECKING,
41
+ )
42
+
43
+ if TYPE_CHECKING:
44
+ from jaclang.vendor.pygls.server import LanguageServer, WebSocketTransportAdapter
45
+
46
+
47
+ import attrs
48
+ from cattrs.errors import ClassValidationError
49
+ from jaclang.vendor.pygls.lsprotocol import converters
50
+
51
+ from jaclang.vendor.pygls.capabilities import ServerCapabilitiesBuilder
52
+ from jaclang.vendor.pygls.constants import ATTR_FEATURE_TYPE
53
+ from jaclang.vendor.pygls.exceptions import (
54
+ JsonRpcException,
55
+ JsonRpcInternalError,
56
+ JsonRpcInvalidParams,
57
+ JsonRpcMethodNotFound,
58
+ JsonRpcRequestCancelled,
59
+ FeatureNotificationError,
60
+ FeatureRequestError,
61
+ )
62
+ from jaclang.vendor.pygls.feature_manager import (
63
+ FeatureManager,
64
+ assign_help_attrs,
65
+ is_thread_function,
66
+ )
67
+ from jaclang.vendor.pygls.lsp import ConfigCallbackType, ShowDocumentCallbackType
68
+ from jaclang.vendor.pygls.lsprotocol.types import (
69
+ CANCEL_REQUEST,
70
+ CLIENT_REGISTER_CAPABILITY,
71
+ CLIENT_UNREGISTER_CAPABILITY,
72
+ EXIT,
73
+ INITIALIZE,
74
+ INITIALIZED,
75
+ METHOD_TO_TYPES,
76
+ NOTEBOOK_DOCUMENT_DID_CHANGE,
77
+ NOTEBOOK_DOCUMENT_DID_CLOSE,
78
+ NOTEBOOK_DOCUMENT_DID_OPEN,
79
+ LOG_TRACE,
80
+ SET_TRACE,
81
+ SHUTDOWN,
82
+ TEXT_DOCUMENT_DID_CHANGE,
83
+ TEXT_DOCUMENT_DID_CLOSE,
84
+ TEXT_DOCUMENT_DID_OPEN,
85
+ TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS,
86
+ WINDOW_LOG_MESSAGE,
87
+ WINDOW_SHOW_DOCUMENT,
88
+ WINDOW_SHOW_MESSAGE,
89
+ WINDOW_WORK_DONE_PROGRESS_CANCEL,
90
+ WORKSPACE_APPLY_EDIT,
91
+ WORKSPACE_CONFIGURATION,
92
+ WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS,
93
+ WORKSPACE_EXECUTE_COMMAND,
94
+ WORKSPACE_SEMANTIC_TOKENS_REFRESH,
95
+ )
96
+ from jaclang.vendor.pygls.lsprotocol.types import (
97
+ ApplyWorkspaceEditParams,
98
+ Diagnostic,
99
+ DidChangeNotebookDocumentParams,
100
+ DidChangeTextDocumentParams,
101
+ DidChangeWorkspaceFoldersParams,
102
+ DidCloseNotebookDocumentParams,
103
+ DidCloseTextDocumentParams,
104
+ DidOpenNotebookDocumentParams,
105
+ DidOpenTextDocumentParams,
106
+ ExecuteCommandParams,
107
+ InitializeParams,
108
+ InitializeResult,
109
+ LogMessageParams,
110
+ LogTraceParams,
111
+ MessageType,
112
+ PublishDiagnosticsParams,
113
+ RegistrationParams,
114
+ ResponseErrorMessage,
115
+ SetTraceParams,
116
+ ShowDocumentParams,
117
+ ShowMessageParams,
118
+ TraceValues,
119
+ UnregistrationParams,
120
+ WorkspaceApplyEditResponse,
121
+ WorkspaceEdit,
122
+ InitializeResultServerInfoType,
123
+ WorkspaceConfigurationParams,
124
+ WorkDoneProgressCancelParams,
125
+ )
126
+ from jaclang.vendor.pygls.uris import from_fs_path
127
+ from jaclang.vendor.pygls.workspace import Workspace
128
+
129
+ logger = logging.getLogger(__name__)
130
+
131
+ F = TypeVar("F", bound=Callable)
132
+
133
+
134
+ def call_user_feature(base_func, method_name):
135
+ """Wraps generic LSP features and calls user registered feature
136
+ immediately after it.
137
+ """
138
+
139
+ @functools.wraps(base_func)
140
+ def decorator(self, *args, **kwargs):
141
+ ret_val = base_func(self, *args, **kwargs)
142
+
143
+ try:
144
+ user_func = self.fm.features[method_name]
145
+ self._execute_notification(user_func, *args, **kwargs)
146
+ except KeyError:
147
+ pass
148
+ except Exception:
149
+ logger.exception(
150
+ 'Failed to handle user defined notification "%s": %s', method_name, args
151
+ )
152
+
153
+ return ret_val
154
+
155
+ return decorator
156
+
157
+
158
+ @attrs.define
159
+ class JsonRPCNotification:
160
+ """A class that represents a generic json rpc notification message.
161
+ Used as a fallback for unknown types.
162
+ """
163
+
164
+ method: str
165
+ jsonrpc: str
166
+ params: Any
167
+
168
+
169
+ @attrs.define
170
+ class JsonRPCRequestMessage:
171
+ """A class that represents a generic json rpc request message.
172
+ Used as a fallback for unknown types.
173
+ """
174
+
175
+ id: Union[int, str]
176
+ method: str
177
+ jsonrpc: str
178
+ params: Any
179
+
180
+
181
+ @attrs.define
182
+ class JsonRPCResponseMessage:
183
+ """A class that represents a generic json rpc response message.
184
+ Used as a fallback for unknown types.
185
+ """
186
+
187
+ id: Union[int, str]
188
+ jsonrpc: str
189
+ result: Any
190
+
191
+
192
+ def _dict_to_object(d: Any):
193
+ """Create nested objects (namedtuple) from dict."""
194
+
195
+ if d is None:
196
+ return None
197
+
198
+ if not isinstance(d, dict):
199
+ return d
200
+
201
+ type_name = d.pop("type_name", "Object")
202
+ return json.loads(
203
+ json.dumps(d),
204
+ object_hook=lambda p: namedtuple(type_name, p.keys(), rename=True)(*p.values()),
205
+ )
206
+
207
+
208
+ def _params_field_structure_hook(obj, cls):
209
+ if "params" in obj:
210
+ obj["params"] = _dict_to_object(obj["params"])
211
+
212
+ return cls(**obj)
213
+
214
+
215
+ def _result_field_structure_hook(obj, cls):
216
+ if "result" in obj:
217
+ obj["result"] = _dict_to_object(obj["result"])
218
+
219
+ return cls(**obj)
220
+
221
+
222
+ def default_converter():
223
+ """Default converter factory function."""
224
+
225
+ converter = converters.get_converter()
226
+ converter.register_structure_hook(
227
+ JsonRPCRequestMessage, _params_field_structure_hook
228
+ )
229
+
230
+ converter.register_structure_hook(
231
+ JsonRPCResponseMessage, _result_field_structure_hook
232
+ )
233
+
234
+ converter.register_structure_hook(JsonRPCNotification, _params_field_structure_hook)
235
+
236
+ return converter
237
+
238
+
239
+ class JsonRPCProtocol(asyncio.Protocol):
240
+ """Json RPC protocol implementation using on top of `asyncio.Protocol`.
241
+
242
+ Specification of the protocol can be found here:
243
+ https://www.jsonrpc.org/specification
244
+
245
+ This class provides bidirectional communication which is needed for LSP.
246
+ """
247
+
248
+ CHARSET = "utf-8"
249
+ CONTENT_TYPE = "application/vscode-jsonrpc"
250
+
251
+ MESSAGE_PATTERN = re.compile(
252
+ rb"^(?:[^\r\n]+\r\n)*"
253
+ + rb"Content-Length: (?P<length>\d+)\r\n"
254
+ + rb"(?:[^\r\n]+\r\n)*\r\n"
255
+ + rb"(?P<body>{.*)",
256
+ re.DOTALL,
257
+ )
258
+
259
+ VERSION = "2.0"
260
+
261
+ def __init__(self, server: LanguageServer, converter):
262
+ self._server = server
263
+ self._converter = converter
264
+
265
+ self._shutdown = False
266
+
267
+ # Book keeping for in-flight requests
268
+ self._request_futures: Dict[str, Future[Any]] = {}
269
+ self._result_types: Dict[str, Any] = {}
270
+
271
+ self.fm = FeatureManager(server)
272
+ self.transport: Optional[
273
+ Union[asyncio.WriteTransport, WebSocketTransportAdapter]
274
+ ] = None
275
+ self._message_buf: List[bytes] = []
276
+
277
+ self._send_only_body = False
278
+
279
+ def __call__(self):
280
+ return self
281
+
282
+ def _execute_notification(self, handler, *params):
283
+ """Executes notification message handler."""
284
+ if asyncio.iscoroutinefunction(handler):
285
+ future = asyncio.ensure_future(handler(*params))
286
+ future.add_done_callback(self._execute_notification_callback)
287
+ else:
288
+ if is_thread_function(handler):
289
+ self._server.thread_pool.apply_async(handler, (*params,))
290
+ else:
291
+ handler(*params)
292
+
293
+ def _execute_notification_callback(self, future):
294
+ """Success callback used for coroutine notification message."""
295
+ if future.exception():
296
+ try:
297
+ raise future.exception()
298
+ except Exception:
299
+ error = JsonRpcInternalError.of(sys.exc_info()).to_dict()
300
+ logger.exception('Exception occurred in notification: "%s"', error)
301
+
302
+ # Revisit. Client does not support response with msg_id = None
303
+ # https://stackoverflow.com/questions/31091376/json-rpc-2-0-allow-notifications-to-have-an-error-response
304
+ # self._send_response(None, error=error)
305
+
306
+ def _execute_request(self, msg_id, handler, params):
307
+ """Executes request message handler."""
308
+
309
+ if asyncio.iscoroutinefunction(handler):
310
+ future = asyncio.ensure_future(handler(params))
311
+ self._request_futures[msg_id] = future
312
+ future.add_done_callback(partial(self._execute_request_callback, msg_id))
313
+ else:
314
+ # Can't be canceled
315
+ if is_thread_function(handler):
316
+ self._server.thread_pool.apply_async(
317
+ handler,
318
+ (params,),
319
+ callback=partial(
320
+ self._send_response,
321
+ msg_id,
322
+ ),
323
+ error_callback=partial(self._execute_request_err_callback, msg_id),
324
+ )
325
+ else:
326
+ self._send_response(msg_id, handler(params))
327
+
328
+ def _execute_request_callback(self, msg_id, future):
329
+ """Success callback used for coroutine request message."""
330
+ try:
331
+ if not future.cancelled():
332
+ self._send_response(msg_id, result=future.result())
333
+ else:
334
+ self._send_response(
335
+ msg_id,
336
+ error=JsonRpcRequestCancelled(
337
+ f'Request with id "{msg_id}" is canceled'
338
+ ),
339
+ )
340
+ self._request_futures.pop(msg_id, None)
341
+ except Exception:
342
+ error = JsonRpcInternalError.of(sys.exc_info()).to_dict()
343
+ logger.exception('Exception occurred for message "%s": %s', msg_id, error)
344
+ self._send_response(msg_id, error=error)
345
+
346
+ def _execute_request_err_callback(self, msg_id, exc):
347
+ """Error callback used for coroutine request message."""
348
+ exc_info = (type(exc), exc, None)
349
+ error = JsonRpcInternalError.of(exc_info).to_dict()
350
+ logger.exception('Exception occurred for message "%s": %s', msg_id, error)
351
+ self._send_response(msg_id, error=error)
352
+
353
+ def _get_handler(self, feature_name):
354
+ """Returns builtin or used defined feature by name if exists."""
355
+ try:
356
+ return self.fm.builtin_features[feature_name]
357
+ except KeyError:
358
+ try:
359
+ return self.fm.features[feature_name]
360
+ except KeyError:
361
+ raise JsonRpcMethodNotFound.of(feature_name)
362
+
363
+ def _handle_cancel_notification(self, msg_id):
364
+ """Handles a cancel notification from the client."""
365
+ future = self._request_futures.pop(msg_id, None)
366
+
367
+ if not future:
368
+ logger.warning('Cancel notification for unknown message id "%s"', msg_id)
369
+ return
370
+
371
+ # Will only work if the request hasn't started executing
372
+ if future.cancel():
373
+ logger.info('Cancelled request with id "%s"', msg_id)
374
+
375
+ def _handle_notification(self, method_name, params):
376
+ """Handles a notification from the client."""
377
+ if method_name == CANCEL_REQUEST:
378
+ self._handle_cancel_notification(params.id)
379
+ return
380
+
381
+ try:
382
+ handler = self._get_handler(method_name)
383
+ self._execute_notification(handler, params)
384
+ except (KeyError, JsonRpcMethodNotFound):
385
+ logger.warning('Ignoring notification for unknown method "%s"', method_name)
386
+ except Exception as error:
387
+ logger.exception(
388
+ 'Failed to handle notification "%s": %s',
389
+ method_name,
390
+ params,
391
+ exc_info=True,
392
+ )
393
+ self._server._report_server_error(error, FeatureNotificationError)
394
+
395
+ def _handle_request(self, msg_id, method_name, params):
396
+ """Handles a request from the client."""
397
+ try:
398
+ handler = self._get_handler(method_name)
399
+
400
+ # workspace/executeCommand is a special case
401
+ if method_name == WORKSPACE_EXECUTE_COMMAND:
402
+ handler(params, msg_id)
403
+ else:
404
+ self._execute_request(msg_id, handler, params)
405
+
406
+ except JsonRpcException as error:
407
+ logger.exception(
408
+ "Failed to handle request %s %s %s",
409
+ msg_id,
410
+ method_name,
411
+ params,
412
+ exc_info=True,
413
+ )
414
+ self._send_response(msg_id, None, error.to_dict())
415
+ self._server._report_server_error(error, FeatureRequestError)
416
+ except Exception as error:
417
+ logger.exception(
418
+ "Failed to handle request %s %s %s",
419
+ msg_id,
420
+ method_name,
421
+ params,
422
+ exc_info=True,
423
+ )
424
+ err = JsonRpcInternalError.of(sys.exc_info()).to_dict()
425
+ self._send_response(msg_id, None, err)
426
+ self._server._report_server_error(error, FeatureRequestError)
427
+
428
+ def _handle_response(self, msg_id, result=None, error=None):
429
+ """Handles a response from the client."""
430
+ future = self._request_futures.pop(msg_id, None)
431
+
432
+ if not future:
433
+ logger.warning('Received response to unknown message id "%s"', msg_id)
434
+ return
435
+
436
+ if error is not None:
437
+ logger.debug('Received error response to message "%s": %s', msg_id, error)
438
+ future.set_exception(JsonRpcException.from_error(error))
439
+ else:
440
+ logger.debug('Received result for message "%s": %s', msg_id, result)
441
+ future.set_result(result)
442
+
443
+ def _serialize_message(self, data):
444
+ """Function used to serialize data sent to the client."""
445
+
446
+ if hasattr(data, "__attrs_attrs__"):
447
+ return self._converter.unstructure(data)
448
+
449
+ if isinstance(data, enum.Enum):
450
+ return data.value
451
+
452
+ return data.__dict__
453
+
454
+ def _deserialize_message(self, data):
455
+ """Function used to deserialize data recevied from the client."""
456
+
457
+ if "jsonrpc" not in data:
458
+ return data
459
+
460
+ try:
461
+ if "id" in data:
462
+ if "error" in data:
463
+ return self._converter.structure(data, ResponseErrorMessage)
464
+ elif "method" in data:
465
+ request_type = (
466
+ self.get_message_type(data["method"]) or JsonRPCRequestMessage
467
+ )
468
+ return self._converter.structure(data, request_type)
469
+ else:
470
+ response_type = (
471
+ self._result_types.pop(data["id"]) or JsonRPCResponseMessage
472
+ )
473
+ return self._converter.structure(data, response_type)
474
+
475
+ else:
476
+ method = data.get("method", "")
477
+ notification_type = self.get_message_type(method) or JsonRPCNotification
478
+ return self._converter.structure(data, notification_type)
479
+
480
+ except ClassValidationError as exc:
481
+ logger.error("Unable to deserialize message\n%s", traceback.format_exc())
482
+ raise JsonRpcInvalidParams() from exc
483
+
484
+ except Exception as exc:
485
+ logger.error("Unable to deserialize message\n%s", traceback.format_exc())
486
+ raise JsonRpcInternalError() from exc
487
+
488
+ def _procedure_handler(self, message):
489
+ """Delegates message to handlers depending on message type."""
490
+
491
+ if message.jsonrpc != JsonRPCProtocol.VERSION:
492
+ logger.warning('Unknown message "%s"', message)
493
+ return
494
+
495
+ if self._shutdown and getattr(message, "method", "") != EXIT:
496
+ logger.warning("Server shutting down. No more requests!")
497
+ return
498
+
499
+ if hasattr(message, "method"):
500
+ if hasattr(message, "id"):
501
+ logger.debug("Request message received.")
502
+ self._handle_request(message.id, message.method, message.params)
503
+ else:
504
+ logger.debug("Notification message received.")
505
+ self._handle_notification(message.method, message.params)
506
+ else:
507
+ if hasattr(message, "error"):
508
+ logger.debug("Error message received.")
509
+ self._handle_response(message.id, None, message.error)
510
+ else:
511
+ logger.debug("Response message received.")
512
+ self._handle_response(message.id, message.result)
513
+
514
+ def _send_data(self, data):
515
+ """Sends data to the client."""
516
+ if not data:
517
+ return
518
+
519
+ if self.transport is None:
520
+ logger.error("Unable to send data, no available transport!")
521
+ return
522
+
523
+ try:
524
+ body = json.dumps(data, default=self._serialize_message)
525
+ logger.info("Sending data: %s", body)
526
+
527
+ if self._send_only_body:
528
+ # Mypy/Pyright seem to think `write()` wants `"bytes | bytearray | memoryview"`
529
+ # But runtime errors with anything but `str`.
530
+ self.transport.write(body) # type: ignore
531
+ return
532
+
533
+ header = (
534
+ f"Content-Length: {len(body)}\r\n"
535
+ f"Content-Type: {self.CONTENT_TYPE}; charset={self.CHARSET}\r\n\r\n"
536
+ ).encode(self.CHARSET)
537
+
538
+ self.transport.write(header + body.encode(self.CHARSET))
539
+ except Exception as error:
540
+ logger.exception("Error sending data", exc_info=True)
541
+ self._server._report_server_error(error, JsonRpcInternalError)
542
+
543
+ def _send_response(self, msg_id, result=None, error=None):
544
+ """Sends a JSON RPC response to the client.
545
+
546
+ Args:
547
+ msg_id(str): Id from request
548
+ result(any): Result returned by handler
549
+ error(any): Error returned by handler
550
+ """
551
+
552
+ if error is not None:
553
+ response = ResponseErrorMessage(id=msg_id, error=error)
554
+
555
+ else:
556
+ response_type = self._result_types.pop(msg_id, JsonRPCResponseMessage)
557
+ response = response_type(
558
+ id=msg_id, result=result, jsonrpc=JsonRPCProtocol.VERSION
559
+ )
560
+
561
+ self._send_data(response)
562
+
563
+ def connection_lost(self, exc):
564
+ """Method from base class, called when connection is lost, in which case we
565
+ want to shutdown the server's process as well.
566
+ """
567
+ logger.error("Connection to the client is lost! Shutting down the server.")
568
+ sys.exit(1)
569
+
570
+ def connection_made( # type: ignore # see: https://github.com/python/typeshed/issues/3021
571
+ self,
572
+ transport: asyncio.Transport,
573
+ ):
574
+ """Method from base class, called when connection is established"""
575
+ self.transport = transport
576
+
577
+ def data_received(self, data: bytes):
578
+ try:
579
+ self._data_received(data)
580
+ except Exception as error:
581
+ logger.exception("Error receiving data", exc_info=True)
582
+ self._server._report_server_error(error, JsonRpcInternalError)
583
+
584
+ def _data_received(self, data: bytes):
585
+ """Method from base class, called when server receives the data"""
586
+ logger.debug("Received %r", data)
587
+
588
+ while len(data):
589
+ # Append the incoming chunk to the message buffer
590
+ self._message_buf.append(data)
591
+
592
+ # Look for the body of the message
593
+ message = b"".join(self._message_buf)
594
+ found = JsonRPCProtocol.MESSAGE_PATTERN.fullmatch(message)
595
+
596
+ body = found.group("body") if found else b""
597
+ length = int(found.group("length")) if found else 1
598
+
599
+ if len(body) < length:
600
+ # Message is incomplete; bail until more data arrives
601
+ return
602
+
603
+ # Message is complete;
604
+ # extract the body and any remaining data,
605
+ # and reset the buffer for the next message
606
+ body, data = body[:length], body[length:]
607
+ self._message_buf = []
608
+
609
+ # Parse the body
610
+ self._procedure_handler(
611
+ json.loads(
612
+ body.decode(self.CHARSET), object_hook=self._deserialize_message
613
+ )
614
+ )
615
+
616
+ def get_message_type(self, method: str) -> Optional[Type]:
617
+ """Return the type definition of the message associated with the given method."""
618
+ return None
619
+
620
+ def get_result_type(self, method: str) -> Optional[Type]:
621
+ """Return the type definition of the result associated with the given method."""
622
+ return None
623
+
624
+ def notify(self, method: str, params=None):
625
+ """Sends a JSON RPC notification to the client."""
626
+
627
+ logger.debug("Sending notification: '%s' %s", method, params)
628
+
629
+ notification_type = self.get_message_type(method) or JsonRPCNotification
630
+ notification = notification_type(
631
+ method=method, params=params, jsonrpc=JsonRPCProtocol.VERSION
632
+ )
633
+
634
+ self._send_data(notification)
635
+
636
+ def send_request(self, method, params=None, callback=None, msg_id=None):
637
+ """Sends a JSON RPC request to the client.
638
+
639
+ Args:
640
+ method(str): The method name of the message to send
641
+ params(any): The payload of the message
642
+
643
+ Returns:
644
+ Future that will be resolved once a response has been received
645
+ """
646
+
647
+ if msg_id is None:
648
+ msg_id = str(uuid.uuid4())
649
+
650
+ request_type = self.get_message_type(method) or JsonRPCRequestMessage
651
+ logger.debug('Sending request with id "%s": %s %s', msg_id, method, params)
652
+
653
+ request = request_type(
654
+ id=msg_id,
655
+ method=method,
656
+ params=params,
657
+ jsonrpc=JsonRPCProtocol.VERSION,
658
+ )
659
+
660
+ future = Future() # type: ignore[var-annotated]
661
+ # If callback function is given, call it when result is received
662
+ if callback:
663
+
664
+ def wrapper(future: Future):
665
+ result = future.result()
666
+ logger.info("Client response for %s received: %s", params, result)
667
+ callback(result)
668
+
669
+ future.add_done_callback(wrapper)
670
+
671
+ self._request_futures[msg_id] = future
672
+ self._result_types[msg_id] = self.get_result_type(method)
673
+
674
+ self._send_data(request)
675
+
676
+ return future
677
+
678
+ def send_request_async(self, method, params=None, msg_id=None):
679
+ """Calls `send_request` and wraps `concurrent.futures.Future` with
680
+ `asyncio.Future` so it can be used with `await` keyword.
681
+
682
+ Args:
683
+ method(str): The method name of the message to send
684
+ params(any): The payload of the message
685
+ msg_id(str|int): Optional, message id
686
+
687
+ Returns:
688
+ `asyncio.Future` that can be awaited
689
+ """
690
+ return asyncio.wrap_future(
691
+ self.send_request(method, params=params, msg_id=msg_id)
692
+ )
693
+
694
+ def thread(self):
695
+ """Decorator that mark function to execute it in a thread."""
696
+ return self.fm.thread()
697
+
698
+
699
+ def lsp_method(method_name: str) -> Callable[[F], F]:
700
+ def decorator(f: F) -> F:
701
+ f.method_name = method_name # type: ignore[attr-defined]
702
+ return f
703
+
704
+ return decorator
705
+
706
+
707
+ class LSPMeta(type):
708
+ """Wraps LSP built-in features (`lsp_` naming convention).
709
+
710
+ Built-in features cannot be overridden but user defined features with
711
+ the same LSP name will be called after them.
712
+ """
713
+
714
+ def __new__(mcs, cls_name, cls_bases, cls):
715
+ for attr_name, attr_val in cls.items():
716
+ if callable(attr_val) and hasattr(attr_val, "method_name"):
717
+ method_name = attr_val.method_name
718
+ wrapped = call_user_feature(attr_val, method_name)
719
+ assign_help_attrs(wrapped, method_name, ATTR_FEATURE_TYPE)
720
+ cls[attr_name] = wrapped
721
+
722
+ logger.debug('Added decorator for lsp method: "%s"', attr_name)
723
+
724
+ return super().__new__(mcs, cls_name, cls_bases, cls)
725
+
726
+
727
+ class LanguageServerProtocol(JsonRPCProtocol, metaclass=LSPMeta):
728
+ """A class that represents language server protocol.
729
+
730
+ It contains implementations for generic LSP features.
731
+
732
+ Attributes:
733
+ workspace(Workspace): In memory workspace
734
+ """
735
+
736
+ def __init__(self, server, converter):
737
+ super().__init__(server, converter)
738
+
739
+ self._workspace: Optional[Workspace] = None
740
+ self.trace = None
741
+
742
+ from jaclang.vendor.pygls.progress import Progress
743
+
744
+ self.progress = Progress(self)
745
+
746
+ self.server_info = InitializeResultServerInfoType(
747
+ name=server.name,
748
+ version=server.version,
749
+ )
750
+
751
+ self._register_builtin_features()
752
+
753
+ def _register_builtin_features(self):
754
+ """Registers generic LSP features from this class."""
755
+ for name in dir(self):
756
+ if name in {"workspace"}:
757
+ continue
758
+
759
+ attr = getattr(self, name)
760
+ if callable(attr) and hasattr(attr, "method_name"):
761
+ self.fm.add_builtin_feature(attr.method_name, attr)
762
+
763
+ @property
764
+ def workspace(self) -> Workspace:
765
+ if self._workspace is None:
766
+ raise RuntimeError(
767
+ "The workspace is not available - has the server been initialized?"
768
+ )
769
+
770
+ return self._workspace
771
+
772
+ @lru_cache()
773
+ def get_message_type(self, method: str) -> Optional[Type]:
774
+ """Return LSP type definitions, as provided by `lsprotocol`"""
775
+ return METHOD_TO_TYPES.get(method, (None,))[0]
776
+
777
+ @lru_cache()
778
+ def get_result_type(self, method: str) -> Optional[Type]:
779
+ return METHOD_TO_TYPES.get(method, (None, None))[1]
780
+
781
+ def apply_edit(
782
+ self, edit: WorkspaceEdit, label: Optional[str] = None
783
+ ) -> WorkspaceApplyEditResponse:
784
+ """Sends apply edit request to the client."""
785
+ return self.send_request(
786
+ WORKSPACE_APPLY_EDIT, ApplyWorkspaceEditParams(edit=edit, label=label)
787
+ )
788
+
789
+ def apply_edit_async(
790
+ self, edit: WorkspaceEdit, label: Optional[str] = None
791
+ ) -> WorkspaceApplyEditResponse:
792
+ """Sends apply edit request to the client. Should be called with `await`"""
793
+ return self.send_request_async(
794
+ WORKSPACE_APPLY_EDIT, ApplyWorkspaceEditParams(edit=edit, label=label)
795
+ )
796
+
797
+ @lsp_method(EXIT)
798
+ def lsp_exit(self, *args) -> None:
799
+ """Stops the server process."""
800
+ if self.transport is not None:
801
+ self.transport.close()
802
+
803
+ sys.exit(0 if self._shutdown else 1)
804
+
805
+ @lsp_method(INITIALIZE)
806
+ def lsp_initialize(self, params: InitializeParams) -> InitializeResult:
807
+ """Method that initializes language server.
808
+ It will compute and return server capabilities based on
809
+ registered features.
810
+ """
811
+ logger.info("Language server initialized %s", params)
812
+
813
+ self._server.process_id = params.process_id
814
+
815
+ text_document_sync_kind = self._server._text_document_sync_kind
816
+ notebook_document_sync = self._server._notebook_document_sync
817
+
818
+ # Initialize server capabilities
819
+ self.client_capabilities = params.capabilities
820
+ self.server_capabilities = ServerCapabilitiesBuilder(
821
+ self.client_capabilities,
822
+ set({**self.fm.features, **self.fm.builtin_features}.keys()),
823
+ self.fm.feature_options,
824
+ list(self.fm.commands.keys()),
825
+ text_document_sync_kind,
826
+ notebook_document_sync,
827
+ ).build()
828
+ logger.debug(
829
+ "Server capabilities: %s",
830
+ json.dumps(self.server_capabilities, default=self._serialize_message),
831
+ )
832
+
833
+ root_path = params.root_path
834
+ root_uri = params.root_uri
835
+ if root_path is not None and root_uri is None:
836
+ root_uri = from_fs_path(root_path)
837
+
838
+ # Initialize the workspace
839
+ workspace_folders = params.workspace_folders or []
840
+ self._workspace = Workspace(
841
+ root_uri,
842
+ text_document_sync_kind,
843
+ workspace_folders,
844
+ self.server_capabilities.position_encoding,
845
+ )
846
+
847
+ self.trace = TraceValues.Off
848
+
849
+ return InitializeResult(
850
+ capabilities=self.server_capabilities,
851
+ server_info=self.server_info,
852
+ )
853
+
854
+ @lsp_method(INITIALIZED)
855
+ def lsp_initialized(self, *args) -> None:
856
+ """Notification received when client and server are connected."""
857
+ pass
858
+
859
+ @lsp_method(SHUTDOWN)
860
+ def lsp_shutdown(self, *args) -> None:
861
+ """Request from client which asks server to shutdown."""
862
+ for future in self._request_futures.values():
863
+ future.cancel()
864
+
865
+ self._shutdown = True
866
+ return None
867
+
868
+ @lsp_method(TEXT_DOCUMENT_DID_CHANGE)
869
+ def lsp_text_document__did_change(
870
+ self, params: DidChangeTextDocumentParams
871
+ ) -> None:
872
+ """Updates document's content.
873
+ (Incremental(from server capabilities); not configurable for now)
874
+ """
875
+ for change in params.content_changes:
876
+ self.workspace.update_text_document(params.text_document, change)
877
+
878
+ @lsp_method(TEXT_DOCUMENT_DID_CLOSE)
879
+ def lsp_text_document__did_close(self, params: DidCloseTextDocumentParams) -> None:
880
+ """Removes document from workspace."""
881
+ self.workspace.remove_text_document(params.text_document.uri)
882
+
883
+ @lsp_method(TEXT_DOCUMENT_DID_OPEN)
884
+ def lsp_text_document__did_open(self, params: DidOpenTextDocumentParams) -> None:
885
+ """Puts document to the workspace."""
886
+ self.workspace.put_text_document(params.text_document)
887
+
888
+ @lsp_method(NOTEBOOK_DOCUMENT_DID_OPEN)
889
+ def lsp_notebook_document__did_open(
890
+ self, params: DidOpenNotebookDocumentParams
891
+ ) -> None:
892
+ """Put a notebook document into the workspace"""
893
+ self.workspace.put_notebook_document(params)
894
+
895
+ @lsp_method(NOTEBOOK_DOCUMENT_DID_CHANGE)
896
+ def lsp_notebook_document__did_change(
897
+ self, params: DidChangeNotebookDocumentParams
898
+ ) -> None:
899
+ """Update a notebook's contents"""
900
+ self.workspace.update_notebook_document(params)
901
+
902
+ @lsp_method(NOTEBOOK_DOCUMENT_DID_CLOSE)
903
+ def lsp_notebook_document__did_close(
904
+ self, params: DidCloseNotebookDocumentParams
905
+ ) -> None:
906
+ """Remove a notebook document from the workspace."""
907
+ self.workspace.remove_notebook_document(params)
908
+
909
+ @lsp_method(SET_TRACE)
910
+ def lsp_set_trace(self, params: SetTraceParams) -> None:
911
+ """Changes server trace value."""
912
+ self.trace = params.value
913
+
914
+ @lsp_method(WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS)
915
+ def lsp_workspace__did_change_workspace_folders(
916
+ self, params: DidChangeWorkspaceFoldersParams
917
+ ) -> None:
918
+ """Adds/Removes folders from the workspace."""
919
+ logger.info("Workspace folders changed: %s", params)
920
+
921
+ added_folders = params.event.added or []
922
+ removed_folders = params.event.removed or []
923
+
924
+ for f_add, f_remove in zip_longest(added_folders, removed_folders):
925
+ if f_add:
926
+ self.workspace.add_folder(f_add)
927
+ if f_remove:
928
+ self.workspace.remove_folder(f_remove.uri)
929
+
930
+ @lsp_method(WORKSPACE_EXECUTE_COMMAND)
931
+ def lsp_workspace__execute_command(
932
+ self, params: ExecuteCommandParams, msg_id: str
933
+ ) -> None:
934
+ """Executes commands with passed arguments and returns a value."""
935
+ cmd_handler = self.fm.commands[params.command]
936
+ self._execute_request(msg_id, cmd_handler, params.arguments)
937
+
938
+ @lsp_method(WINDOW_WORK_DONE_PROGRESS_CANCEL)
939
+ def lsp_work_done_progress_cancel(
940
+ self, params: WorkDoneProgressCancelParams
941
+ ) -> None:
942
+ """Received a progress cancellation from client."""
943
+ future = self.progress.tokens.get(params.token)
944
+ if future is None:
945
+ logger.warning(
946
+ "Ignoring work done progress cancel for unknown token %s", params.token
947
+ )
948
+ else:
949
+ future.cancel()
950
+
951
+ def get_configuration(
952
+ self,
953
+ params: WorkspaceConfigurationParams,
954
+ callback: Optional[ConfigCallbackType] = None,
955
+ ) -> Future:
956
+ """Sends configuration request to the client.
957
+
958
+ Args:
959
+ params(WorkspaceConfigurationParams): WorkspaceConfigurationParams from lsp specs
960
+ callback(callable): Callabe which will be called after
961
+ response from the client is received
962
+ Returns:
963
+ concurrent.futures.Future object that will be resolved once a
964
+ response has been received
965
+ """
966
+ return self.send_request(WORKSPACE_CONFIGURATION, params, callback)
967
+
968
+ def get_configuration_async(
969
+ self, params: WorkspaceConfigurationParams
970
+ ) -> asyncio.Future:
971
+ """Calls `get_configuration` method but designed to use with coroutines
972
+
973
+ Args:
974
+ params(WorkspaceConfigurationParams): WorkspaceConfigurationParams from lsp specs
975
+ Returns:
976
+ asyncio.Future that can be awaited
977
+ """
978
+ return asyncio.wrap_future(self.get_configuration(params))
979
+
980
+ def log_trace(self, message: str, verbose: Optional[str] = None) -> None:
981
+ """Sends trace notification to the client."""
982
+ if self.trace == TraceValues.Off:
983
+ return
984
+
985
+ params = LogTraceParams(message=message)
986
+ if verbose and self.trace == TraceValues.Verbose:
987
+ params.verbose = verbose
988
+
989
+ self.notify(LOG_TRACE, params)
990
+
991
+ def _publish_diagnostics_deprecator(
992
+ self,
993
+ params_or_uri: Union[str, PublishDiagnosticsParams],
994
+ diagnostics: Optional[List[Diagnostic]],
995
+ version: Optional[int],
996
+ **kwargs,
997
+ ) -> PublishDiagnosticsParams:
998
+ if isinstance(params_or_uri, str):
999
+ message = "DEPRECATION: "
1000
+ "`publish_diagnostics("
1001
+ "self, doc_uri: str, diagnostics: List[Diagnostic], version: Optional[int] = None)`"
1002
+ "will be replaced with `publish_diagnostics(self, params: PublishDiagnosticsParams)`"
1003
+ logging.warning(message)
1004
+
1005
+ params = self._construct_publish_diagnostic_type(
1006
+ params_or_uri, diagnostics, version, **kwargs
1007
+ )
1008
+ else:
1009
+ params = params_or_uri
1010
+ return params
1011
+
1012
+ def _construct_publish_diagnostic_type(
1013
+ self,
1014
+ uri: str,
1015
+ diagnostics: Optional[List[Diagnostic]],
1016
+ version: Optional[int],
1017
+ **kwargs,
1018
+ ) -> PublishDiagnosticsParams:
1019
+ if diagnostics is None:
1020
+ diagnostics = []
1021
+
1022
+ args = {
1023
+ **{"uri": uri, "diagnostics": diagnostics, "version": version},
1024
+ **kwargs,
1025
+ }
1026
+
1027
+ params = PublishDiagnosticsParams(**args) # type:ignore
1028
+ return params
1029
+
1030
+ def publish_diagnostics(
1031
+ self,
1032
+ params_or_uri: Union[str, PublishDiagnosticsParams],
1033
+ diagnostics: Optional[List[Diagnostic]] = None,
1034
+ version: Optional[int] = None,
1035
+ **kwargs,
1036
+ ):
1037
+ """Sends diagnostic notification to the client.
1038
+
1039
+ .. deprecated:: 1.0.1
1040
+
1041
+ Passing ``(uri, diagnostics, version)`` as arguments is deprecated.
1042
+ Pass an instance of :class:`~lsprotocol.types.PublishDiagnosticParams`
1043
+ instead.
1044
+
1045
+ Parameters
1046
+ ----------
1047
+ params_or_uri
1048
+ The :class:`~lsprotocol.types.PublishDiagnosticParams` to send to the client.
1049
+
1050
+ diagnostics
1051
+ *Deprecated*. The diagnostics to publish
1052
+
1053
+ version
1054
+ *Deprecated*: The version number
1055
+ """
1056
+ params = self._publish_diagnostics_deprecator(
1057
+ params_or_uri, diagnostics, version, **kwargs
1058
+ )
1059
+ self.notify(TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS, params)
1060
+
1061
+ def register_capability(
1062
+ self, params: RegistrationParams, callback: Optional[Callable[[], None]] = None
1063
+ ) -> Future:
1064
+ """Register a new capability on the client.
1065
+
1066
+ Args:
1067
+ params(RegistrationParams): RegistrationParams from lsp specs
1068
+ callback(callable): Callabe which will be called after
1069
+ response from the client is received
1070
+ Returns:
1071
+ concurrent.futures.Future object that will be resolved once a
1072
+ response has been received
1073
+ """
1074
+ return self.send_request(CLIENT_REGISTER_CAPABILITY, params, callback)
1075
+
1076
+ def register_capability_async(self, params: RegistrationParams) -> asyncio.Future:
1077
+ """Register a new capability on the client.
1078
+
1079
+ Args:
1080
+ params(RegistrationParams): RegistrationParams from lsp specs
1081
+
1082
+ Returns:
1083
+ asyncio.Future object that will be resolved once a
1084
+ response has been received
1085
+ """
1086
+ return asyncio.wrap_future(self.register_capability(params, None))
1087
+
1088
+ def semantic_tokens_refresh(
1089
+ self, callback: Optional[Callable[[], None]] = None
1090
+ ) -> Future:
1091
+ """Requesting a refresh of all semantic tokens.
1092
+
1093
+ Args:
1094
+ callback(callable): Callabe which will be called after
1095
+ response from the client is received
1096
+
1097
+ Returns:
1098
+ concurrent.futures.Future object that will be resolved once a
1099
+ response has been received
1100
+ """
1101
+ return self.send_request(WORKSPACE_SEMANTIC_TOKENS_REFRESH, callback=callback)
1102
+
1103
+ def semantic_tokens_refresh_async(self) -> asyncio.Future:
1104
+ """Requesting a refresh of all semantic tokens.
1105
+
1106
+ Returns:
1107
+ asyncio.Future object that will be resolved once a
1108
+ response has been received
1109
+ """
1110
+ return asyncio.wrap_future(self.semantic_tokens_refresh(None))
1111
+
1112
+ def show_document(
1113
+ self,
1114
+ params: ShowDocumentParams,
1115
+ callback: Optional[ShowDocumentCallbackType] = None,
1116
+ ) -> Future:
1117
+ """Display a particular document in the user interface.
1118
+
1119
+ Args:
1120
+ params(ShowDocumentParams): ShowDocumentParams from lsp specs
1121
+ callback(callable): Callabe which will be called after
1122
+ response from the client is received
1123
+
1124
+ Returns:
1125
+ concurrent.futures.Future object that will be resolved once a
1126
+ response has been received
1127
+ """
1128
+ return self.send_request(WINDOW_SHOW_DOCUMENT, params, callback)
1129
+
1130
+ def show_document_async(self, params: ShowDocumentParams) -> asyncio.Future:
1131
+ """Display a particular document in the user interface.
1132
+
1133
+ Args:
1134
+ params(ShowDocumentParams): ShowDocumentParams from lsp specs
1135
+
1136
+ Returns:
1137
+ asyncio.Future object that will be resolved once a
1138
+ response has been received
1139
+ """
1140
+ return asyncio.wrap_future(self.show_document(params, None))
1141
+
1142
+ def show_message(self, message, msg_type=MessageType.Info):
1143
+ """Sends message to the client to display message."""
1144
+ self.notify(
1145
+ WINDOW_SHOW_MESSAGE, ShowMessageParams(type=msg_type, message=message)
1146
+ )
1147
+
1148
+ def show_message_log(self, message, msg_type=MessageType.Log):
1149
+ """Sends message to the client's output channel."""
1150
+ self.notify(
1151
+ WINDOW_LOG_MESSAGE, LogMessageParams(type=msg_type, message=message)
1152
+ )
1153
+
1154
+ def unregister_capability(
1155
+ self,
1156
+ params: UnregistrationParams,
1157
+ callback: Optional[Callable[[], None]] = None,
1158
+ ) -> Future:
1159
+ """Unregister a new capability on the client.
1160
+
1161
+ Args:
1162
+ params(UnregistrationParams): UnregistrationParams from lsp specs
1163
+ callback(callable): Callabe which will be called after
1164
+ response from the client is received
1165
+ Returns:
1166
+ concurrent.futures.Future object that will be resolved once a
1167
+ response has been received
1168
+ """
1169
+ return self.send_request(CLIENT_UNREGISTER_CAPABILITY, params, callback)
1170
+
1171
+ def unregister_capability_async(
1172
+ self, params: UnregistrationParams
1173
+ ) -> asyncio.Future:
1174
+ """Unregister a new capability on the client.
1175
+
1176
+ Args:
1177
+ params(UnregistrationParams): UnregistrationParams from lsp specs
1178
+ callback(callable): Callabe which will be called after
1179
+ response from the client is received
1180
+ Returns:
1181
+ asyncio.Future object that will be resolved once a
1182
+ response has been received
1183
+ """
1184
+ return asyncio.wrap_future(self.unregister_capability(params, None))