diff --git a/LSP.sublime-settings b/LSP.sublime-settings index 6cb35033c..d5ed44adc 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -342,6 +342,15 @@ // // If the server supports `diagnosticProvider.workspaceDiagnostics`, // // diagnostics are requested for all files in the project folders. // "diagnostics_mode": "open_files", + // + // // Map the paths of URIs in the data exchanged between the server and the client. + // // + // // WARNING: Due to its working principle of modifying the interaction data between + // // the client and the server, it cannot identify the source of the content in the + // // data. If your code file happens to start with a URI and meets the mapping conditions, + // // it may inadvertently send incorrect messages to the server. However, such situations + // // should be virtually nonexistent. + // "path_maps": [ {"local": "file:///C:", "remote": "file:///mnt/c"} ] // } // } "clients": {}, diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 79f8a3d5c..79e6a6bf1 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -2383,6 +2383,7 @@ def exit(self) -> None: def send_payload(self, payload: dict[str, Any]) -> None: try: + payload = self.config.map_uri_on_payload(payload, is_from_client_to_server=True) self.transport.send(payload) # type: ignore except AttributeError: pass @@ -2425,6 +2426,7 @@ def deduce_payload( return (None, None, None, None, None) def on_payload(self, payload: dict[str, Any]) -> None: + payload = self.config.map_uri_on_payload(payload, is_from_client_to_server=False) handler, result, req_id, typestr, _method = self.deduce_payload(payload) if handler: try: diff --git a/plugin/core/types.py b/plugin/core/types.py index b5d5b932f..74c29bd93 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -845,6 +845,24 @@ def set_view_status(self, view: sublime.View, message: str) -> None: def erase_view_status(self, view: sublime.View) -> None: view.erase_status(self.status_key) + def map_uri_on_payload(self, payload: Any, is_from_client_to_server: bool) -> Any: + if isinstance(payload, dict): + for k, v in payload.items(): + payload[k] = self.map_uri_on_payload(v, is_from_client_to_server) + + if isinstance(payload, list): + for i, v in enumerate(payload): + payload[i] = self.map_uri_on_payload(v, is_from_client_to_server) + + if isinstance(payload, str) and payload.startswith("file://") and self.path_maps: + for path_map in self.path_maps: + path, mapped = path_map.map_from_local_to_remote(payload) if is_from_client_to_server else \ + path_map.map_from_remote_to_local(payload) + if mapped: + payload = path + + return payload + def match_view(self, view: sublime.View, scheme: str) -> bool: syntax = view.syntax() if not syntax: @@ -855,22 +873,12 @@ def match_view(self, view: sublime.View, scheme: str) -> bool: return scheme in self.schemes and sublime.score_selector(syntax.scope, selector) > 0 def map_client_path_to_server_uri(self, path: str) -> str: - if self.path_maps: - for path_map in self.path_maps: - path, mapped = path_map.map_from_local_to_remote(path) - if mapped: - break - return filename_to_uri(path) + return self.map_uri_on_payload(filename_to_uri(path), is_from_client_to_server=True) def map_server_uri_to_client_path(self, uri: str) -> str: - scheme, path = parse_uri(uri) + scheme, path = parse_uri(self.map_uri_on_payload(uri, is_from_client_to_server=False)) if scheme not in ("file", "res"): raise ValueError(f"{uri}: {scheme} URI scheme is unsupported") - if self.path_maps: - for path_map in self.path_maps: - path, mapped = path_map.map_from_remote_to_local(path) - if mapped: - break return path def is_disabled_capability(self, capability_path: str) -> bool: diff --git a/tests/test_configs.py b/tests/test_configs.py index ef1e2ea94..b2fa610bd 100644 --- a/tests/test_configs.py +++ b/tests/test_configs.py @@ -145,12 +145,12 @@ def test_path_maps(self): "selector": "source.foo", "path_maps": [ { - "local": "/home/user/projects/myproject", - "remote": "/workspace" + "local": "file:///home/user/projects/myproject", + "remote": "file:///workspace" }, { - "local": "/home/user/projects/another", - "remote": "/workspace2" + "local": "file:///home/user/projects/another", + "remote": "file:///workspace2" } ] })