Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update textDocument/documentSymbol parsing to LSP 3.10.0 spec #303

Closed
wants to merge 2 commits into from

Conversation

ilohmar
Copy link
Collaborator

@ilohmar ilohmar commented Sep 22, 2019

https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol

The code is correct, I hope, but possibly very inelegant, as it is the
first time I have worked with the eglot-* macros.

Also note: xref-backend-identifier-completion-table needs the same
parsing, but I have not had a closer look at the xref part yet. I think
we should parse in one place, to a structure keeping all information,
and then cast that into the necessary form for either xref or imenu.


ilohmar pushed a commit to ilohmar/eglot that referenced this pull request Sep 23, 2019
…tavora#303)

* eglot (eglot-imenu): Use helper function to parse DocumentSymbol tree.
@nemethf
Copy link
Collaborator

nemethf commented Sep 27, 2019

This seems useful, but I'm not familiar with this part of the code, so I'd rather not comment the code changes. However, there's a pending pull request (#213) also modifying imenu related code. There, João asked for writing accompanying tests. I think it's not a must, but can you do that for this PR?

@joaotavora
Copy link
Owner

@ilohmar As @nemethf mentions, I think tests are a good idea, if for no other reason, to better understand what this is about here (I have limited time to follow the spec nowadays).

I also see there's a recursive call to eglot--parse-DocumentSymbol. Can you explain why?

@joaotavora
Copy link
Owner

I also see there's a recursive call to eglot--parse-DocumentSymbol. Can you explain why?

Nevermind, I see it's a recursive data structure, so recursiveness makes sense.

@ilohmar
Copy link
Collaborator Author

ilohmar commented Sep 28, 2019

Yeah, it's actually a tree (although I have no clue yet how to best use this for imenu).. :)

I will try to get around to writing tests, but preferably by mocking the behavior of the language server, instead of relying on actual servers being available.

In any case, that would probably only happen after I figure out how to extract the parsing from the xref part as well. Are there any comments explaining how that works? It seems to cache identifiers from the current buffer or sth like that..?

@joaotavora
Copy link
Owner

@ilohmar do you know of any other server that supports this? I was hoping I could avoid installing gopls.

@ilohmar
Copy link
Collaborator Author

ilohmar commented Oct 24, 2019

Sorry, I have only used pyls, gopls and clangd myself. Have you ever worked with Go? I understand trying to avoid dependencies, however, the actual installation itself is easy and fast.

@galeo
Copy link
Contributor

galeo commented Dec 9, 2019

@ilohmar do you know of any other server that supports this? I was hoping I could avoid installing gopls.

Hi @joaotavora

AFAIK, the Microsoft‘s python-language-server and Apple's swift language server sourcekit-lsp support textDocument/documentSymbol feature.

I'm looking forward to seeing this feature supported by eglot.

@joaotavora
Copy link
Owner

AFAIK, the Microsoft‘s python-language-server and Apple's swift language server sourcekit-lsp support textDocument/documentSymbol feature.

I'm not in a position to install any of those right now. But this is indeed in my queue. I will clean it up and put it in a side repo where you can test with those servers

joaotavora pushed a commit to ilohmar/eglot that referenced this pull request Dec 9, 2019
…tavora#303)

* eglot (eglot-imenu): Use helper function to parse DocumentSymbol tree.
@joaotavora
Copy link
Owner

joaotavora commented Dec 9, 2019

I just resolved some conflicts and now it applies cleanly on master. But I haven't tested in any way.

@muffinmad
Copy link
Collaborator

@ilohmar Please specify hierarchicalDocumentSymbolSupport in the TextDocumentClientCapabilities.documentSymbol as well. This way server will know that we support this feature.

@sstepashka
Copy link

Is there way to prioritize the PR? :)

@joaotavora
Copy link
Owner

Is there way to prioritize the PR? :)

I get the message. It helps if you can confirm that it applies cleanly to master, addresses @muffinmad 's comment and works correctly for at least one server where it wasn't working before. Post your results here, please. Thanks.

@joaotavora
Copy link
Owner

To be clear: doing any of those things helps, you don't have to do all of them to be useful.

Ingo Lohmar and others added 2 commits May 2, 2020 11:55
…tavora#303)

* eglot (eglot-imenu): Use helper function to parse DocumentSymbol tree.
* eglot.el (eglot-client-capabilities, defvar): Add
DocumentSymbol.
(eglot-client-capabilities): Add
:hierarchicalDocumentSymbolSupport.
(eglot--parse-DocumentSymbol): Remove.
(eglot-imenu): Rewrite.
@joaotavora
Copy link
Owner

I've pushed some changes to the implementation, in hopes of simplifying it, but I don't have any server to test with yet. Maybe someone can do that testing for me?

@joaotavora joaotavora closed this in da04fdc May 2, 2020
@sstepashka
Copy link

Sorry fo delay. It works! thank you very much!

@muffinmad
Copy link
Collaborator

Thanks @joaotavora !

I can't test this feature right now, but I notice that Eglot is now sending textDocument/documentSymbol even if server reported :documentSymbolProvider :json-false in textDocumentSync capabilities.

@joaotavora
Copy link
Owner

I can't test this feature right now, but I notice that Eglot is now sending
textDocument/documentSymbol even if server reported :documentSymbolProvider :json-false in
textDocumentSync capabilities.

Ahh, good catch. A simple if should do. Or maybe an eglot-error? Not sure if that's a good idea since other stuff will call this function non-interactively.

@muffinmad
Copy link
Collaborator

Example python file:

def some_function():
    def some_inline_function():
        pass
    pass


class SomeClassName:
    foo = 1

    def method_name(self):
        pass


class SomeOtherClass:
    foo = 2

    def method_name(self):
        pass

For that file the server responded to the documentSymbol request with the following hierarchical DocumentSymbol list:

(:id 2 :jsonrpc "2.0" :result
     [(:name "some_function" :kind 12 :range
	     (:start
	      (:line 0 :character 4)
	      :end
	      (:line 0 :character 20))
	     :selectionRange
	     (:start
	      (:line 0 :character 4)
	      :end
	      (:line 0 :character 20))
	     :detail nil :children
	     [(:name "some_inline_function" :kind 12 :range
		     (:start
		      (:line 1 :character 8)
		      :end
		      (:line 1 :character 31))
		     :selectionRange
		     (:start
		      (:line 1 :character 8)
		      :end
		      (:line 1 :character 31))
		     :detail nil :children nil :deprecated :json-false)]
	     :deprecated :json-false)
      (:name "SomeClassName" :kind 5 :range
	     (:start
	      (:line 6 :character 6)
	      :end
	      (:line 6 :character 20))
	     :selectionRange
	     (:start
	      (:line 6 :character 6)
	      :end
	      (:line 6 :character 20))
	     :detail nil :children
	     [(:name "foo" :kind 13 :range
		     (:start
		      (:line 7 :character 4)
		      :end
		      (:line 7 :character 11))
		     :selectionRange
		     (:start
		      (:line 7 :character 4)
		      :end
		      (:line 7 :character 11))
		     :detail nil :children nil :deprecated :json-false)
	      (:name "method_name" :kind 12 :range
		     (:start
		      (:line 9 :character 8)
		      :end
		      (:line 9 :character 26))
		     :selectionRange
		     (:start
		      (:line 9 :character 8)
		      :end
		      (:line 9 :character 26))
		     :detail nil :children nil :deprecated :json-false)]
	     :deprecated :json-false)
      (:name "SomeOtherClass" :kind 5 :range
	     (:start
	      (:line 13 :character 6)
	      :end
	      (:line 13 :character 21))
	     :selectionRange
	     (:start
	      (:line 13 :character 6)
	      :end
	      (:line 13 :character 21))
	     :detail nil :children
	     [(:name "foo" :kind 13 :range
		     (:start
		      (:line 14 :character 4)
		      :end
		      (:line 14 :character 11))
		     :selectionRange
		     (:start
		      (:line 14 :character 4)
		      :end
		      (:line 14 :character 11))
		     :detail nil :children nil :deprecated :json-false)
	      (:name "method_name" :kind 12 :range
		     (:start
		      (:line 16 :character 8)
		      :end
		      (:line 16 :character 26))
		     :selectionRange
		     (:start
		      (:line 16 :character 8)
		      :end
		      (:line 16 :character 26))
		     :detail nil :children nil :deprecated :json-false)]
	     :deprecated :json-false)])

The Imenu structure now looks like this:

+ Class
   SomeClassName
   SomeOtherClass
+ Variable
   + SomeClassName
     foo
   + SomeOtherClass
     foo
+ Function
   some_function
   + some_function
     some_inline_function
   + SomeClassName
     method_name
   + SomeOtherClass
     method_name

I used to Imenu structure provided by python-imenu-create-flat-index that looks like this (for the same file):

+ some_function (def)
   *function definition*
   some_inline_function (def)
+ SomeClassName (class)
   *class definition*
   method_name (def)
+ SomeOtherClass (class)
   *class definition*
   method_name (def)

I found the later Imenu structure more compact, intuitive and easy to use. No need to think about type of item to navigate to at the first place.

Maybe it would be better to not group Imenu items by item type but only by hierarchical structure?

What do you think?

P.S. The python language server is anakinls. The documentSymbol implementation is not published on pypi yet, so in case someone want to check it in action, please install it from master.

@joaotavora
Copy link
Owner

No need to think about type of item to navigate to at the first place.

Yes, I agree. imenu is doing needless restructuring: it shouldn't. The reason it does it is historical I think: there were no DocumentSymbol trees before. BUt now that there are, there's no point in doing this. I'll check this later.

bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 18, 2022
…lot-imenu

A reworking of an original implementation by Ingo Lohmar
<ingo.lohmar@github.com>

* eglot.el (eglot-client-capabilities, defvar): Add
DocumentSymbol.
(eglot-client-capabilities): Add
:hierarchicalDocumentSymbolSupport.
(eglot--parse-DocumentSymbol): Remove.
(eglot-imenu): Rewrite.

* NEWS.md (1.7): Mention new feature
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
…lot-imenu

A reworking of an original implementation by Ingo Lohmar
<ingo.lohmar@github.com>

* eglot.el (eglot-client-capabilities, defvar): Add
DocumentSymbol.
(eglot-client-capabilities): Add
:hierarchicalDocumentSymbolSupport.
(eglot--parse-DocumentSymbol): Remove.
(eglot-imenu): Rewrite.

* NEWS.md (1.7): Mention new feature
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
A reworking of an original implementation by Ingo Lohmar
<ingo.lohmar@github.com>

* eglot.el (eglot-client-capabilities, defvar): Add
DocumentSymbol.
(eglot-client-capabilities): Add
:hierarchicalDocumentSymbolSupport.
(eglot--parse-DocumentSymbol): Remove.
(eglot-imenu): Rewrite.

* NEWS.md (1.7): Mention new feature

#303: joaotavora/eglot#303
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
A reworking of an original implementation by Ingo Lohmar
<ingo.lohmar@github.com>

* eglot.el (eglot-client-capabilities, defvar): Add
DocumentSymbol.
(eglot-client-capabilities): Add
:hierarchicalDocumentSymbolSupport.
(eglot--parse-DocumentSymbol): Remove.
(eglot-imenu): Rewrite.

* NEWS.md (1.7): Mention new feature

GitHub-reference: close joaotavora/eglot#303
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants