Repository: sublimelsp/LSP

Issue:
Backslash in hover popup is not shown
**Describe the bug**

As the title.

Original response payload:

```
:: <<< LSP-intelephense 22: {'range': {'start': {'line': 4, 'character': 6}, 'end': {'line': 4, 'character': 9}}, 'contents': {'kind': 'markdown', 'value': '__A\\B\\C\\Foo__\n\n```php\n<?php\nclass Foo { }\n```'}}
```

**To Reproduce**

Steps to reproduce the behavior:

1. Have the following codes with intelephense.

```php
<?php

namespace A\B\C;

class Foo {}
```

2. Hover on `Foo`

**Expected behavior**

The backslashes show as-is.

**Screenshots**

![image](https://user-images.githubusercontent.com/6594915/210172533-ef8677f8-1aed-431a-bd8e-4b4de194343c.png)

**Environment (please complete the following information):**
- OS: Win10 x64 22H2
- Sublime Text version: 4147
- LSP version: [4070-1.21.0](https://github.com/sublimelsp/LSP/releases/tag/4070-1.21.0)
- Language servers used: intelephense



Discussion:
Minimal reproduce:

```py
mdpopups.show_popup(view, mdpopups.md2html(view, mdpopups.format_frontmatter({'markdown_extensions': [{'pymdownx.escapeall': {}}]}) + '__A\\B\\C\\Foo__'))
```

I'll have to throw it at @facelessuser  :)
Please reference the documentation for the plugin: https://facelessuser.github.io/pymdown-extensions/extensions/escapeall/.

If you have any questions or confusion about its behavior after reading, please feel free to ask. I feel like the documentation is pretty clear, but I'm happy to update if there is anything unclear.

Right, makes sense.

The [PR that added `pymdownx.escapeall`](https://github.com/sublimelsp/LSP/pull/1188) doesn't reference any issues but I believe it was meant to fix https://github.com/sublimelsp/LSP-css/pull/16 and the  `LSP-css` case seems to be working now without `pymdownx.escapeall` (probably fixed in the language server itself) so I would lean towards just removing that extension.
Though the `hardbreak` option of `pymdownx.escapeall` was later enabled in https://github.com/sublimelsp/LSP/pull/1591 to fix a different case. And that case still seems to need this workaround.

So it appears that we might still need `pymdownx.escapeall` for `hardbreak` case while we don't want it for processing anything else. Which doesn't seem to be possible right now.
🤷🏻 If you are using unescaped HTML characters, you run the risk of things breaking. In this case, HTML entities or escapes for HTML characters should most likely be used, but EscapeAll is a great alternative. Something like `<color>` (referencing the case above, should not be expected to just work.

The original Markdown spec does not include `<` into the default list of characters that can be escaped: https://daringfireball.net/projects/markdown/syntax#backslash. I assume the idea was that that was what HTML entities were for.

Anyways, some or even all CommonMark parsers may support escaped `\<` now, not sure what they are currently spec'd to do in this regard, but historically, that was not the case.

EscapeAll has a very specific goal in what it is doing. I wanted `\` to always escape so I didn't have to think about whether a plugin allowed a certain character to be escaped or not, especially when you are using a number of custom extensions. It isn't trying to match CommonMark as it existed well before CommonMark started making its appearance.
On the other hand, pyright doesn't seem to be formatting the content in a way that needs this workaround anymore:

![Screenshot 2023-01-01 at 16 54 01](https://user-images.githubusercontent.com/153197/210176907-617812fb-703d-427a-a8ce-7c5f30850408.png)

```
{
  "label": "AMQPConnectionWorkflow",
  "data": {
    "workspacePath": "/usr/local/workspace/sublime-packages/LSP",
    "symbolLabel": "AMQPConnectionWorkflow",
    "filePath": "/usr/local/workspace/sublime-packages/LSP/plugin/completion.py",
    "position": {
      "character": 5,
      "line": 19
    }
  },
  "kind": 7,
  "documentation": {
    "value": "```python\nclass AMQPConnectionWorkflow()\n```\n---\nImplements Pika's default workflow for performing multiple TCP/\\[SSL\\]/AMQP\nconnection attempts with timeouts and retries until one succeeds or all\nattempts fail.\n\nThe workflow:  \n&nbsp;&nbsp;&nbsp;&nbsp;while not success and retries remain:\n        1. For each given config (pika.connection.Parameters object):  \n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A. Perform DNS resolution of the config's host.\nB. Attempt to establish TCP/\\[SSL\\]/AMQP for each resolved address  \n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;until one succeeds, in which case we're done.\n        2. If all configs failed but retries remain, resume from beginning  \n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;after the given retry pause. NOTE: failure of DNS resolution\nis equivalent to one cycle and will be retried after the pause\nif retries remain.",
    "kind": "markdown"
  },
  "sortText": "05.0000.AMQPConnectionWorkflow"
}
```

So it seems like we can drop it after all.
To summarize, both of the cases that needed `pymdownx.escapeall` don't seem to be an issue anymore (likely fixed in the relevant servers). We might find this issue popping up again in other cases if we drop the `pymdownx.escapeall` extension but it feels like it's the way to go for now anyway.

Resolving patch:
diff --git a/plugin/core/views.py b/plugin/core/views.py
--- a/plugin/core/views.py
+++ b/plugin/core/views.py
@@ -720,12 +720,6 @@ def minihtml(
             "allow_code_wrap": True,
             "markdown_extensions": [
                 "markdown.extensions.admonition",
-                {
-                    "pymdownx.escapeall": {
-                        "hardbreak": True,
-                        "nbsp": False
-                    }
-                },
                 {
                     "pymdownx.magiclink": {
                         # links are displayed without the initial ftp://, http://, https://, or ftps://.


Test patch:
diff --git a/tests/test_views.py b/tests/test_views.py
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -396,5 +396,11 @@ def test_format_diagnostic_for_html(self) -> None:
     def test_escaped_newline_in_markdown(self) -> None:
         self.assertEqual(
             minihtml(self.view, {"kind": "markdown", "value": "hello\\\nworld"}, FORMAT_MARKUP_CONTENT),
-            "<p>hello<br />\nworld</p>"
+            "<p>hello\\\nworld</p>"
+        )
+
+    def test_single_backslash_in_markdown(self) -> None:
+        self.assertEqual(
+            minihtml(self.view, {"kind": "markdown", "value": "A\\B"}, FORMAT_MARKUP_CONTENT),
+            "<p>A\\B</p>"
         )