sublimelsp / LSP

Client implementation of the Language Server Protocol for Sublime Text
https://lsp.sublimetext.io/
MIT License
1.65k stars 180 forks source link

Can't navigate to JARs #1844

Closed askonomm closed 2 years ago

askonomm commented 3 years ago

Describe the bug When using Clojure LSP, you cannot navigate to external dependencies which are located inside of JAR files, because of invalid URI scheme. When trying to navigate to the path shown in the popup, it just opens that in the browser instead, where it fails. I've already had a discussion about this in the Clojure LSP repo, and the conclusion there was that it is the fault of Sublime LSP.

To Reproduce Steps to reproduce the behavior:

  1. Install Clojure LSP
  2. Open a project with any external dependencies whether it would be in namespaces or in function calls
  3. Try go-to-ing to any of them
  4. See error

Expected behavior I expect it would open the file inside the JAR and go to the code bit I wanted to go to.

Screenshots

132616920-7bc9875d-2641-462e-ae53-33232aefb381 132616927-3fabebf5-e7fb-4f0d-b500-60e30f13bdba

Environment (please complete the following information):

Additional context Add any other context about the problem here. For example, whether you're using a helper package or your manual server configuration in LSP.sublime-settings. When using a manual server configuration please include it here if you believe it's applicable.

rwols commented 3 years ago

Based on the RPC log in the linked issue we are dealing with a textDocument/definition request with responses that contain an URI like this one:

jar:file:///Users/asko/.m2/repository/markdown-clj/markdown-clj/1.10.6/markdown-clj-1.10.6.jar!/markdown/core.clj

To handle an URI with scheme jar, one would have to write a helper plugin that would handle such schemes and provide the content and appropriate syntax. A basic general-purpose language configuration as specified in Packages/User/LSP.sublime-settings can only handle the file scheme.

Examples of packages that handle custom URI schemes:

Someone would have to put in the effort to write that.

rchl commented 3 years ago

Though clicking on the path in the popup is probably a separate thing to solve? It looks like an URI created by mdpopups and it's just handled natively by ST.

rwols commented 3 years ago

Yes, we could make changes to let that flow through the uri handling stuff as well.

askonomm commented 3 years ago

I'm not a pro with Python, but I can totally attempt writing a helper plugin, if that's cool?

rwols commented 3 years ago

I can totally attempt writing a helper plugin

Sure thing. Look at LSP-Deno for a basic example on how to implement that. See also https://github.com/sublimelsp/LSP/blob/main/plugin/core/sessions.py#L420

rwols commented 3 years ago

We also have a Discord channel if you need any help or have any questions https://discord.com/channels/280102180189634562/645268178397560865

aiyogi01 commented 2 years ago

I'm not a pro with SublimeText plugins, but could a solution look like this?

It works on my machine, though there is still a slight oddity: After opening a definition to an external dependency and closing that tab again, the clojure-lsp seems not to provide URIs to that external dependency any more. If the tab is kept open, everything works fine. As a work-around I had to intercept the notification "textDocument/didClose", so that the language server never receives it, even if the tab is actually closed.

Packages/LSP-ClojureHelper/clojure.py:

import sublime
import urllib.parse
import zipfile

from LSP.plugin import AbstractPlugin, Request, register_plugin, unregister_plugin
from LSP.plugin.core.typing import Callable
from LSP.plugin.core.views import text_document_identifier

class ClojureHelper(AbstractPlugin):
    """
    Helper plugin for `clojure-lsp`.

    The main use case is proper handling of zip-resources, like:
        "zipfile:///Users/<user>/.m2/repository/re-frame/re-frame/1.2.0/re-frame-1.2.0.jar::re_frame/core.cljc"
    """

    @classmethod
    def name(cls) -> str:
        return cls.__name__

    def on_pre_send_notification_async(self, notification) -> None:
        # Is there a bug in `clojure-lsp`? After closing a tab with an external dependency definition
        # no URIs to that external dependency are provided by the language server any more.
        if notification.method == "textDocument/didClose":
            notification.params = {}

    def on_open_uri_async(self, uri: str, callback: Callable[[str, str, str], None]) -> bool:
        if uri.startswith("zipfile:"):
            session = self.weaksession()
            if session:
                try:
                    parsed = urllib.parse.urlparse(uri)
                    archive, file = parsed.path.split("::")
                    with zipfile.ZipFile(archive) as zf:
                        title = file
                        content = zf.read(file).decode("utf-8")
                        syntax = sublime.find_syntax_for_file(file).path
                except Exception as error:
                    title = "ERROR"
                    content = str(error)
                    syntax = "Packages/Text/Plain text.tmLanguage"
                session.send_request_async(
                    Request("textDocument/definition", text_document_identifier(uri), progress=True),
                    lambda response: callback(title, content, syntax),
                    lambda err: callback(title, content, syntax)
                )
            return True
        return False

def plugin_loaded() -> None:
    register_plugin(ClojureHelper)

def plugin_unloaded() -> None:
    unregister_plugin(ClojureHelper)

Packages/LSP-ClojureHelper/LSP-ClojureHelper.sublime-settings:

{
    "enabled": true,
    "selector": "source.clojure",
    "schemes": ["file", "zipfile"],
    "command": ["clojure-lsp"],
    "settings": {}
}
rwols commented 2 years ago

Thanks for your efforts @aiyogi01. In the on_open_uri_async method, you should call the provided callback with the computed title, content and syntax, as in callback(title, content, syntax).

That additional session.send_request_async for textDocument/definition looks very out of place, you should remove that.

predragnikolic commented 2 years ago

The LSP plugin provides a way to for LSP-* plugins to handle this(the on_open_uri_async method).

But someone has to create a LSP-Closure plugin as https://github.com/sublimelsp/LSP/issues/1844#issuecomment-961214237 (althogh withouth the session.send_request_async for textDocument/definition, like mention in the comment above). If someone want to do that feel free to ping me. :) or reach on discord https://discord.com/channels/280102180189634562/645268178397560865

I will close this issue as there is nothing on the LSP side that can be done to address this.