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

Hyperlinks from markdown hover text are unclickable #865

Closed
astoff opened this issue Mar 9, 2022 · 20 comments · Fixed by #866
Closed

Hyperlinks from markdown hover text are unclickable #865

astoff opened this issue Mar 9, 2022 · 20 comments · Fixed by #866

Comments

@astoff
Copy link
Contributor

astoff commented Mar 9, 2022

  • Server used: Digestif
  • Emacs version: 28
  • Operating system: Linux
  • Eglot version: 1.8
  • Eglot installation method: ELPA
  • Using Doom: No

When an Eldoc buffer produced by Eglot contains hyperlinks (because the server sent the hover text in markdown format), the hyperlinks are formatted as such and contain the URL in the help-echo property, but clicking a link doesn't work.

This is because the markdown-mode command that opens the link relies on invisible text around the hyperlink to discover the URL. However, Eglot strips the invisible text in this line:

eglot/eglot.el

Line 1439 in d03235f

(string-trim (filter-buffer-substring (point-min) (point-max))))))

In my opinion, the correct implementation of that function is as follows:

https://github.com/astoff/eglot/blob/b4a416f1c13ce0472944e385b867d79d9277c880/eglot.el#L1439-L1441

Now, the use of filter-buffer-substring originated from #482. The problem was that a specific server would send a hover string that started with "```\n", so when Eldoc would display the first line of the Eldoc buffer in the echo area, the results were poor. Here are my observations:

  • I can't reproduce the reported behavior with pylsp, perhaps the server changed its behavior.
  • On the other hand, I don't know if any other server adds hyperlinks. Digestif does that because most TeX documentation is in PDF format, and pointing to a file for the user to look further is about the best I can do in most cases. (This also makes this issue rather low priority, I guess).
  • Markdown mode is probably not at fault, as discussed here: markdown--filter-visible makes hyperlinks unclickable jrblevin/markdown-mode#693
  • In the problem reported at Use filter-buffer-substring to get buffer text #482, it's arguably Eldoc who's at fault. It should copy one visual line to the echo area and make sure it retains its essential display properties.
@joaotavora
Copy link
Owner

joaotavora commented Mar 9, 2022 via email

astoff added a commit to astoff/eglot that referenced this issue Mar 9, 2022
This was introduced in joaotavora#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Fixes joaotavora#865.

* eglot.el (eglot--format-markup): Don't use
'filter-buffer-substring'; instead, keep invisible text.
@astoff
Copy link
Contributor Author

astoff commented Mar 9, 2022

Okay, I made a pull request. But please take into account that this order of fixing things may break Eldoc for some users, for some time.

@astoff
Copy link
Contributor Author

astoff commented Mar 9, 2022

By the way, we should mention this to @muffinmad, who introduced the change that led to this.

astoff added a commit to astoff/eglot that referenced this issue Mar 10, 2022
This was introduced in joaotavora#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Fixes joaotavora#865.

* eglot.el (eglot--format-markup): Don't use
'filter-buffer-substring'; instead, keep invisible text.
joaotavora pushed a commit that referenced this issue Mar 10, 2022
This was introduced in #482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per #866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring
@muffinmad
Copy link
Collaborator

Sadly, this breaks my setup. I'm using anakin-language-server wich sends hover info like

(:kind "markdown" :value "```python\nint(x: Union[str, bytes, SupportsInt, _SupportsIndex, _SupportsTrunc]=...)\n...

Setting the eldoc-echo-area-use-multiline-p variable to 1 leads to empty echo area instead of the first line of the hover info.

@joaotavora
Copy link
Owner

I don't understand this. Both pre-and and post-change code seems to yield the same value when applied to your example @muffinmad:

(eglot--format-markup "```python\nint(x: Union[str, bytes, SupportsInt, _SupportsIndex, _SupportsTrunc]=...)\n")

returns:

#("```python\nint(x: Union[str, bytes, SupportsInt, _SupportsIndex, _SupportsTrunc]=...)\n```" 0 3
  (face
   (markdown-markup-face markdown-code-face)
   invisible markdown-markup markdown-gfm-block-begin
   (1 10 1 4 4 4 4 10 nil nil 10 10 #<killed buffer>))
  3 9
  (face
   (markdown-language-keyword-face markdown-code-face)
   invisible markdown-markup markdown-gfm-block-begin
   (1 10 1 4 4 4 4 10 nil nil 10 10 #<killed buffer>))
  9 10
  (invisible markdown-markup face
             (markdown-code-face)
             font-lock-multiline t)
  10 85
  (font-lock-multiline t face
                       (markdown-pre-face markdown-code-face)
                       markdown-gfm-code
                       (11 86))
  85 86
  (font-lock-multiline t face
                       (markdown-markup-face markdown-code-face)
                       invisible markdown-markup markdown-gfm-block-end
                       (86 89 86 89 89 89 #<killed buffer>))
  86 87
  (face
   (markdown-markup-face markdown-code-face)
   invisible markdown-markup markdown-gfm-block-end
   (86 89 86 89 89 89 #<killed buffer>))
  87 88
  (face
   (markdown-markup-face markdown-code-face)
   invisible markdown-markup font-lock-multiline t markdown-gfm-block-end
   (86 89 86 89 89 89 #<killed buffer>)))

in both cases. What am I missing?

@astoff
Copy link
Contributor Author

astoff commented Mar 12, 2022

@muffinmad Of course Eglot should work with all sensible servers, but since you are the author of anakin-language-server, may I ask why you add that specific piece of markup? I suppose you want the server to work well on editors that can't format markdown, or slightly mangle it.

@joaotavora
Copy link
Owner

My two cents on the markdown vs non-markdown debate is that I think it's practically a standard now, there's no point in thinking too much about non-support (only a tiny bit ;-) )

My immediate interest here is to make both of you happy. It seems @astoff that all you were missing was hyperlinks right? Or more? Does digestif emit markdown or not?

@astoff
Copy link
Contributor Author

astoff commented Mar 12, 2022

Of course, we should fix the issue @muffinmad reports. Emacs shouldn't be among the editors that slightly mangle markdown rendering. I was just saying that as a server developer I would play safe with the first line of the hover string specifically.

Now, the place we need to look is when Eldoc selects n lines of the Eldoc buffer to display in the echo area. It should be n visual lines, but currently it picks n actual lines.

@muffinmad
Copy link
Collaborator

@muffinmad Of course Eglot should work with all sensible servers, but since you are the author of anakin-language-server, may I ask why you add that specific piece of markup? I suppose you want the server to work well on editors that can't format markdown, or slightly mangle it.

In case the client is not reporting support for hover content in markdown mode, the server will respond with plain text:

(:jsonrpc "2.0" :id 12 :result
	  (:contents
	   (:kind "plaintext" :value "foo(bar: str, baz: int) -> bool\n\nSome docstring.\nUsage example:\n\n    if foo(\"\", 0):\n        return")))

The markdown format is sent only when the client reporting markdown support.

The first part of the hover info is usually the function signature, which is valid python code. So, to have syntax hightlight, it is wrapped in python code block.
The second part of the hover info is wrapped by plain code block in order to use fixed font and preserve indentation.

The whole hover info will look like this:

@muffinmad
Copy link
Collaborator

Also, although the number of visible lines is the same, eldoc desides to truncate the hover info:

The 7 lines of the hover info in plainttext format are fully displayed.

@muffinmad
Copy link
Collaborator

And here is screenshot of the previous behaviour:

@astoff
Copy link
Contributor Author

astoff commented Mar 20, 2022

@muffinmad I understand the idea and the goal. I was just wondering why you want to do this, given that it will almost surely break some editor, even if we fix Eglot :-).

@nemethf
Copy link
Collaborator

nemethf commented Mar 20, 2022

This is a little bit orthogonal to this issue, but if I understand correctly, @muffinmad's underlying assumption is that "the first part of the hover info is usually the function signature". If eldoc-documentation-functions is just '(eglot-signature-eldoc-function), then eldoc will show just the signature. And it seems anakin-language-server is a signatureHelpProvider. So, what's wrong with this setup?

@muffinmad
Copy link
Collaborator

@astoff Some other editor is pretty fine with markdown format. Maybe because they do not try to get the first line of the docs :)

@muffinmad
Copy link
Collaborator

@nemethf In case hover info will not contain signature in the first line, it still be wrapped in code block to preserve indentation

(:jsonrpc "2.0" :id 60 :result
          (:contents
           (:kind "markdown" :value "```\nConcrete date/time and related types.\n\nSee http://www.iana.org/time-zones/repository/tz-link.html for\ntime zone and DST data sources.\n```")))

@astoff
Copy link
Contributor Author

astoff commented Mar 20, 2022

Some other editor is pretty fine with markdown format. Maybe because they do not try to get the first line of the docs :)

I'm sure some other editor will handle that markup just fine. But I'm also sure not every editor will.

In case hover info will not contain signature in the first line, it still be wrapped in code block to preserve indentation

This is clearly a wrong use of a code block, since what's inside the code block is not code. According to the markdown documentation, you can insert a hard break by ending a line with at least two spaces:

$ echo -e 'a\nb  \nc' | pandoc --to html
<p>a b<br />
c</p>

@muffinmad
Copy link
Collaborator

muffinmad commented Mar 20, 2022

I'm sure some other editor will handle that markup just fine. But I'm also sure not every editor will.

If the editor enables markdown format support in hover info, then it is the editor task to handle it properly, right?

This is clearly a wrong use of a code block, since what's inside the code block is not code. According to the markdown documentation, you can insert a hard break by ending a line with at least two spaces:

It's not about line breaks, but about docstring formattig using spaces. And the monospaced font. Here is the example from the docstring of import statement:

The "import" statement
**********************

   import_stmt     ::= "import" module ["as" identifier] ("," module ["as" identifier])*
                   | "from" relative_module "import" identifier ["as" identifier]
                   ("," identifier ["as" identifier])*
                   | "from" relative_module "import" "(" identifier ["as" identifier]
                   ("," identifier ["as" identifier])* [","] ")"
                   | "from" relative_module "import" "*"
   module          ::= (identifier ".")* identifier
   relative_module ::= "."* module | "."+

Can you imagine how it will look like without the <pre>? :)

According to https://daringfireball.net/projects/markdown/syntax#precode

Pre-formatted code blocks are used for writing about programming or markup source code

I don't see it says "code blocks is only for code". Can we classify doscstrings as "writing about programming"? :)

@joaotavora
Copy link
Owner

@muffinmad regardless of your arguments, which are interesting (and on which I don't have a very clear position, due mainly to ignorance and lack of testing on these servers), have you tested @astoff 's patch to eldoc.el in https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54473 ?

Can you tell if it solves your problem completely/partially/not at all?

@muffinmad
Copy link
Collaborator

@joaotavora Not yet. But I will.

@joaotavora
Copy link
Owner

Cool. If possible, please reply to that thread. I think your feedback is more useful there.

mpolden added a commit to mpolden/emacs.d that referenced this issue Apr 5, 2022
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 18, 2022
…hover string

This was introduced in joaotavora/eglot#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per joaotavora/eglot#866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
…hover string

This was introduced in joaotavora/eglot#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per joaotavora/eglot#866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
This was introduced in #482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per #866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring
#865: joaotavora/eglot#865
#482: joaotavora/eglot#482
#866: joaotavora/eglot#866
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 12, 2022
This was introduced in joaotavora/eglot#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per joaotavora/eglot#866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring

GitHub-reference: fix joaotavora/eglot#865
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 20, 2022
This was introduced in joaotavora/eglot#482 due to a bad interaction with a specific
server.  But this solution makes hyperlinks in Eldoc buffers
unclickable, because the markdown-mode function that visits a link
relies on the invisible text.

Per joaotavora/eglot#866 

* eglot.el (eglot--format-markup): Use buffer-string instead of 
filter-buffer-substring

GitHub-reference: fix joaotavora/eglot#865
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 a pull request may close this issue.

4 participants