We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Intelephense v1.0 released with a few issues
I'm happy to announce Intelephense v1.0 is released. More info can be found [here](https://github.com/bmewburn/intelephense-docs)

I'm not entirely sure if this is an LSP issue or a server issue.

When autocompleting method names I have to manually type the parenthesis and tooltip information seems messed up.

![tooltip](https://i.imgur.com/ITBEn6a.png)


* OSX 10.14 - Intelephense 1.0
* Package Control

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plugin/signature_help.py`
Content:
```
1 import mdpopups
2 import sublime
3 import sublime_plugin
4 import webbrowser
5 import re
6 import html
7 
8 try:
9     from typing import Any, List, Dict, Optional
10     assert Any and List and Dict and Optional
11 except ImportError:
12     pass
13 
14 from .core.configurations import is_supported_syntax
15 from .core.registry import config_for_scope, session_for_view, client_for_view
16 from .core.documents import get_document_position
17 from .core.events import global_events
18 from .core.protocol import Request
19 from .core.logging import debug
20 from .core.popups import popup_css, popup_class
21 from .core.settings import settings
22 
23 
24 class SignatureHelpListener(sublime_plugin.ViewEventListener):
25 
26     def __init__(self, view):
27         self.view = view
28         self._initialized = False
29         self._signature_help_triggers = []  # type: List[str]
30         self._visible = False
31         self._language_id = ""
32         self._signatures = []  # type: List[Any]
33         self._active_signature = -1
34         self._active_parameter = -1
35 
36     @classmethod
37     def is_applicable(cls, settings):
38         syntax = settings.get('syntax')
39         return syntax and is_supported_syntax(syntax)
40 
41     def initialize(self):
42         session = session_for_view(self.view)
43         if session:
44             signatureHelpProvider = session.get_capability(
45                 'signatureHelpProvider')
46             if signatureHelpProvider:
47                 self._signature_help_triggers = signatureHelpProvider.get(
48                     'triggerCharacters')
49 
50         config = config_for_scope(self.view)
51         if config:
52             self._language_id = self._view_language(self.view, config.name)
53 
54         self._initialized = True
55 
56     def on_modified_async(self):
57         pos = self.view.sel()[0].begin()
58         # TODO: this will fire too often, narrow down using scopes or regex
59         if not self._initialized:
60             self.initialize()
61 
62         if self._signature_help_triggers:
63             last_char = self.view.substr(pos - 1)
64             if last_char in self._signature_help_triggers:
65                 self.request_signature_help(pos)
66             elif self._visible:
67                 if last_char.isspace():
68                     # Peek behind to find the last non-whitespace character.
69                     last_char = self.view.substr(self.view.find_by_class(pos, False, ~0) - 1)
70                 if last_char not in self._signature_help_triggers:
71                     self.view.hide_popup()
72 
73     def request_signature_help(self, point) -> None:
74         client = client_for_view(self.view)
75         if client:
76             global_events.publish("view.on_purge_changes", self.view)
77             document_position = get_document_position(self.view, point)
78             if document_position:
79                 client.send_request(
80                     Request.signatureHelp(document_position),
81                     lambda response: self.handle_response(response, point))
82 
83     def handle_response(self, response: 'Optional[Dict]', point) -> None:
84         if response is not None:
85             self._signatures = response.get("signatures", [])
86             self._active_signature = response.get("activeSignature", -1)
87             self._active_parameter = response.get("activeParameter", -1)
88 
89             if self._signatures:
90                 if not 0 <= self._active_signature < len(self._signatures):
91                     debug("activeSignature {} not a valid index for signatures length {}".format(
92                         self._active_signature, len(self._signatures)))
93                     self._active_signature = 0
94             else:
95                 if self._active_signature != -1:
96                     debug("activeSignature should be -1 or null when no signatures are returned")
97                     self._active_signature = -1
98 
99             if len(self._signatures) > 0:
100                 if self._visible:
101                     self._update_popup()
102                 else:
103                     self._show_popup(point)
104 
105     def on_query_context(self, key, _, operand, __):
106         if key != "lsp.signature_help":
107             return False  # Let someone else handle this keybinding.
108         elif not self._visible:
109             if operand == 0:
110                 self.request_signature_help(self.view.sel()[0].begin())
111                 return True
112             else:
113                 return False  # Let someone else handle this keybinding.
114         elif len(self._signatures) < 2:
115             return False  # Let someone else handle this keybinding.
116         else:
117             # We use the "operand" for the number -1 or +1. See the keybindings.
118             new_index = self._active_signature + operand
119 
120             # clamp signature index
121             new_index = max(0, min(new_index, len(self._signatures) - 1))
122 
123             # only update when changed
124             if new_index != self._active_signature:
125                 self._active_signature = new_index
126                 self._update_popup()
127 
128             return True  # We handled this keybinding.
129 
130     def _show_popup(self, point: int) -> None:
131         mdpopups.show_popup(self.view,
132                             self._build_popup_content(),
133                             css=popup_css,
134                             md=True,
135                             flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
136                             location=point,
137                             wrapper_class=popup_class,
138                             max_width=800,
139                             on_hide=self._on_hide,
140                             on_navigate=self._on_hover_navigate)
141         self._visible = True
142 
143     def _update_popup(self) -> None:
144         mdpopups.update_popup(self.view,
145                               self._build_popup_content(),
146                               css=popup_css,
147                               md=True,
148                               wrapper_class=popup_class)
149 
150     def _build_popup_content(self) -> str:
151         if settings.highlight_active_signature_parameter:
152             return self._build_popup_content_style_vscode()
153         else:
154             # Default to "sublime".
155             return self._build_popup_content_style_sublime()
156 
157     def _view_language(self, view: sublime.View, config_name: str) -> 'Optional[str]':
158         languages = view.settings().get('lsp_language')
159         return languages.get(config_name) if languages else None
160 
161     def _on_hide(self):
162         self._visible = False
163 
164     def _on_hover_navigate(self, href):
165         webbrowser.open_new_tab(href)
166 
167     def _build_overload_selector(self) -> str:
168         return "**{}** of **{}** overloads (use the ↑ ↓ keys to navigate):\n".format(
169             str(self._active_signature + 1), str(len(self._signatures)))
170 
171     def _build_popup_content_style_sublime(self) -> str:
172         signature = self._signatures[self._active_signature]
173         formatted = []
174 
175         if len(self._signatures) > 1:
176             formatted.append(self._build_overload_selector())
177 
178         signature_label = signature.get('label')
179         if len(signature_label) > 400:
180             label = "```{} ...```".format(signature_label[0:400])  # long code blocks = hangs
181         else:
182             label = "```{}\n{}\n```\n".format(self._language_id, signature_label)
183         formatted.append(label)
184 
185         params = signature.get('parameters')
186         if params:
187             for parameter in params:
188                 paramDocs = parameter.get('documentation', None)
189                 if paramDocs:
190                     formatted.append("**{}**\n".format(parameter.get('label')))
191                     formatted.append("* *{}*\n".format(paramDocs))
192         sigDocs = signature.get('documentation', None)
193         if sigDocs:
194             formatted.append(sigDocs)
195         return "\n".join(formatted)
196 
197     def _build_popup_content_style_vscode(self) -> str:
198         # Fetch all the relevant data.
199         signature_label = ""
200         signature_documentation = ""
201         parameter_label = ""
202         parameter_documentation = ""
203         if self._active_signature in range(0, len(self._signatures)):
204             signature = self._signatures[self._active_signature]
205             signature_label = html.escape(signature["label"], quote=False)
206             signature_documentation = signature.get("documentation", "")  # Optional.
207             parameters = signature.get("parameters", None)
208             if parameters and self._active_parameter in range(0, len(parameters)):
209                 parameter = parameters[self._active_parameter]
210                 parameter_label = html.escape(parameter["label"], quote=False)
211                 parameter_documentation = parameter.get("documentation", "")  # Optional.
212 
213         formatted = []
214 
215         if len(self._signatures) > 1:
216             formatted.append(self._build_overload_selector())
217 
218         # Write the active signature and give special treatment to the active parameter (if found).
219         # Note that this <div> class and the extra <pre> are copied from mdpopups' HTML output. When mdpopups changes
220         # its output style, we must update this literal string accordingly.
221         formatted.append('<div class="highlight"><pre>')
222         if parameter_label:
223             signature_label = self._replace_active_parameter(signature_label, parameter_label)
224         formatted.append(signature_label)
225         formatted.append("</pre></div>")
226 
227         if parameter_documentation:
228             formatted.append(parameter_documentation)
229 
230         if signature_documentation:
231             formatted.append(signature_documentation)
232 
233         return "\n".join(formatted)
234 
235     def _replace_active_parameter(self, signature: str, parameter: str) -> str:
236         if parameter[0].isalnum() and parameter[-1].isalnum():
237             pattern = r'\b{}\b'.format(re.escape(parameter))
238         else:
239             # If the left or right boundary of the parameter string is not an alphanumeric character, the \b check will
240             # never match. In this case, it's probably safe to assume the parameter string itself will be a good pattern
241             # to search for.
242             pattern = re.escape(parameter)
243         replacement = '<span style="font-weight: bold; text-decoration: underline">{}</span>'.format(parameter)
244         # FIXME: This is somewhat language-specific to look for an opening parenthesis. Most languages use parentheses
245         # for their parameter lists though.
246         start_of_param_list_pos = signature.find('(')
247         # Note that this works even when we don't find an opening parenthesis, because .find returns -1 in that case.
248         start_of_param_list = signature[start_of_param_list_pos + 1:]
249         return signature[:start_of_param_list_pos + 1] + re.sub(pattern, replacement, start_of_param_list, 1)
250
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plugin/signature_help.py b/plugin/signature_help.py
--- a/plugin/signature_help.py
+++ b/plugin/signature_help.py
@@ -21,6 +21,22 @@
 from .core.settings import settings
 
 
+def get_documentation(d: 'Dict[str, Any]') -> 'Optional[str]':
+    docs = d.get('documentation', None)
+    if docs is None:
+        return None
+    elif isinstance(docs, str):
+        # In older version of the protocol, documentation was just a string.
+        return docs
+    elif isinstance(docs, dict):
+        # This can be either "plaintext" or "markdown" format. For now, we can dump it into the popup box. It would
+        # be nice to handle the markdown in a special way.
+        return docs.get('value', None)
+    else:
+        debug('unknown documentation type:', str(d))
+        return None
+
+
 class SignatureHelpListener(sublime_plugin.ViewEventListener):
 
     def __init__(self, view):
@@ -185,10 +201,10 @@
         params = signature.get('parameters')
         if params:
             for parameter in params:
-                paramDocs = parameter.get('documentation', None)
-                if paramDocs:
+                param_docs = get_documentation(parameter)
+                if param_docs:
                     formatted.append("**{}**\n".format(parameter.get('label')))
-                    formatted.append("* *{}*\n".format(paramDocs))
+                    formatted.append("* *{}*\n".format(param_docs))
         sigDocs = signature.get('documentation', None)
         if sigDocs:
             formatted.append(sigDocs)
@@ -197,18 +213,18 @@
     def _build_popup_content_style_vscode(self) -> str:
         # Fetch all the relevant data.
         signature_label = ""
-        signature_documentation = ""
+        signature_documentation = ""  # type: Optional[str]
         parameter_label = ""
-        parameter_documentation = ""
+        parameter_documentation = ""  # type: Optional[str]
         if self._active_signature in range(0, len(self._signatures)):
             signature = self._signatures[self._active_signature]
             signature_label = html.escape(signature["label"], quote=False)
-            signature_documentation = signature.get("documentation", "")  # Optional.
+            signature_documentation = get_documentation(signature)
             parameters = signature.get("parameters", None)
             if parameters and self._active_parameter in range(0, len(parameters)):
                 parameter = parameters[self._active_parameter]
                 parameter_label = html.escape(parameter["label"], quote=False)
-                parameter_documentation = parameter.get("documentation", "")  # Optional.
+                parameter_documentation = get_documentation(parameter)
 
         formatted = []

{"golden_diff": "diff --git a/plugin/signature_help.py b/plugin/signature_help.py\n--- a/plugin/signature_help.py\n+++ b/plugin/signature_help.py\n@@ -21,6 +21,22 @@\n from .core.settings import settings\n \n \n+def get_documentation(d: 'Dict[str, Any]') -> 'Optional[str]':\n+    docs = d.get('documentation', None)\n+    if docs is None:\n+        return None\n+    elif isinstance(docs, str):\n+        # In older version of the protocol, documentation was just a string.\n+        return docs\n+    elif isinstance(docs, dict):\n+        # This can be either \"plaintext\" or \"markdown\" format. For now, we can dump it into the popup box. It would\n+        # be nice to handle the markdown in a special way.\n+        return docs.get('value', None)\n+    else:\n+        debug('unknown documentation type:', str(d))\n+        return None\n+\n+\n class SignatureHelpListener(sublime_plugin.ViewEventListener):\n \n     def __init__(self, view):\n@@ -185,10 +201,10 @@\n         params = signature.get('parameters')\n         if params:\n             for parameter in params:\n-                paramDocs = parameter.get('documentation', None)\n-                if paramDocs:\n+                param_docs = get_documentation(parameter)\n+                if param_docs:\n                     formatted.append(\"**{}**\\n\".format(parameter.get('label')))\n-                    formatted.append(\"* *{}*\\n\".format(paramDocs))\n+                    formatted.append(\"* *{}*\\n\".format(param_docs))\n         sigDocs = signature.get('documentation', None)\n         if sigDocs:\n             formatted.append(sigDocs)\n@@ -197,18 +213,18 @@\n     def _build_popup_content_style_vscode(self) -> str:\n         # Fetch all the relevant data.\n         signature_label = \"\"\n-        signature_documentation = \"\"\n+        signature_documentation = \"\"  # type: Optional[str]\n         parameter_label = \"\"\n-        parameter_documentation = \"\"\n+        parameter_documentation = \"\"  # type: Optional[str]\n         if self._active_signature in range(0, len(self._signatures)):\n             signature = self._signatures[self._active_signature]\n             signature_label = html.escape(signature[\"label\"], quote=False)\n-            signature_documentation = signature.get(\"documentation\", \"\")  # Optional.\n+            signature_documentation = get_documentation(signature)\n             parameters = signature.get(\"parameters\", None)\n             if parameters and self._active_parameter in range(0, len(parameters)):\n                 parameter = parameters[self._active_parameter]\n                 parameter_label = html.escape(parameter[\"label\"], quote=False)\n-                parameter_documentation = parameter.get(\"documentation\", \"\")  # Optional.\n+                parameter_documentation = get_documentation(parameter)\n \n         formatted = []\n", "issue": "Intelephense v1.0 released with a few issues\nI'm happy to announce Intelephense v1.0 is released. More info can be found [here](https://github.com/bmewburn/intelephense-docs)\r\n\r\nI'm not entirely sure if this is an LSP issue or a server issue.\r\n\r\nWhen autocompleting method names I have to manually type the parenthesis and tooltip information seems messed up.\r\n\r\n![tooltip](https://i.imgur.com/ITBEn6a.png)\r\n\r\n\r\n* OSX 10.14 - Intelephense 1.0\r\n* Package Control\n", "before_files": [{"content": "import mdpopups\nimport sublime\nimport sublime_plugin\nimport webbrowser\nimport re\nimport html\n\ntry:\n    from typing import Any, List, Dict, Optional\n    assert Any and List and Dict and Optional\nexcept ImportError:\n    pass\n\nfrom .core.configurations import is_supported_syntax\nfrom .core.registry import config_for_scope, session_for_view, client_for_view\nfrom .core.documents import get_document_position\nfrom .core.events import global_events\nfrom .core.protocol import Request\nfrom .core.logging import debug\nfrom .core.popups import popup_css, popup_class\nfrom .core.settings import settings\n\n\nclass SignatureHelpListener(sublime_plugin.ViewEventListener):\n\n    def __init__(self, view):\n        self.view = view\n        self._initialized = False\n        self._signature_help_triggers = []  # type: List[str]\n        self._visible = False\n        self._language_id = \"\"\n        self._signatures = []  # type: List[Any]\n        self._active_signature = -1\n        self._active_parameter = -1\n\n    @classmethod\n    def is_applicable(cls, settings):\n        syntax = settings.get('syntax')\n        return syntax and is_supported_syntax(syntax)\n\n    def initialize(self):\n        session = session_for_view(self.view)\n        if session:\n            signatureHelpProvider = session.get_capability(\n                'signatureHelpProvider')\n            if signatureHelpProvider:\n                self._signature_help_triggers = signatureHelpProvider.get(\n                    'triggerCharacters')\n\n        config = config_for_scope(self.view)\n        if config:\n            self._language_id = self._view_language(self.view, config.name)\n\n        self._initialized = True\n\n    def on_modified_async(self):\n        pos = self.view.sel()[0].begin()\n        # TODO: this will fire too often, narrow down using scopes or regex\n        if not self._initialized:\n            self.initialize()\n\n        if self._signature_help_triggers:\n            last_char = self.view.substr(pos - 1)\n            if last_char in self._signature_help_triggers:\n                self.request_signature_help(pos)\n            elif self._visible:\n                if last_char.isspace():\n                    # Peek behind to find the last non-whitespace character.\n                    last_char = self.view.substr(self.view.find_by_class(pos, False, ~0) - 1)\n                if last_char not in self._signature_help_triggers:\n                    self.view.hide_popup()\n\n    def request_signature_help(self, point) -> None:\n        client = client_for_view(self.view)\n        if client:\n            global_events.publish(\"view.on_purge_changes\", self.view)\n            document_position = get_document_position(self.view, point)\n            if document_position:\n                client.send_request(\n                    Request.signatureHelp(document_position),\n                    lambda response: self.handle_response(response, point))\n\n    def handle_response(self, response: 'Optional[Dict]', point) -> None:\n        if response is not None:\n            self._signatures = response.get(\"signatures\", [])\n            self._active_signature = response.get(\"activeSignature\", -1)\n            self._active_parameter = response.get(\"activeParameter\", -1)\n\n            if self._signatures:\n                if not 0 <= self._active_signature < len(self._signatures):\n                    debug(\"activeSignature {} not a valid index for signatures length {}\".format(\n                        self._active_signature, len(self._signatures)))\n                    self._active_signature = 0\n            else:\n                if self._active_signature != -1:\n                    debug(\"activeSignature should be -1 or null when no signatures are returned\")\n                    self._active_signature = -1\n\n            if len(self._signatures) > 0:\n                if self._visible:\n                    self._update_popup()\n                else:\n                    self._show_popup(point)\n\n    def on_query_context(self, key, _, operand, __):\n        if key != \"lsp.signature_help\":\n            return False  # Let someone else handle this keybinding.\n        elif not self._visible:\n            if operand == 0:\n                self.request_signature_help(self.view.sel()[0].begin())\n                return True\n            else:\n                return False  # Let someone else handle this keybinding.\n        elif len(self._signatures) < 2:\n            return False  # Let someone else handle this keybinding.\n        else:\n            # We use the \"operand\" for the number -1 or +1. See the keybindings.\n            new_index = self._active_signature + operand\n\n            # clamp signature index\n            new_index = max(0, min(new_index, len(self._signatures) - 1))\n\n            # only update when changed\n            if new_index != self._active_signature:\n                self._active_signature = new_index\n                self._update_popup()\n\n            return True  # We handled this keybinding.\n\n    def _show_popup(self, point: int) -> None:\n        mdpopups.show_popup(self.view,\n                            self._build_popup_content(),\n                            css=popup_css,\n                            md=True,\n                            flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,\n                            location=point,\n                            wrapper_class=popup_class,\n                            max_width=800,\n                            on_hide=self._on_hide,\n                            on_navigate=self._on_hover_navigate)\n        self._visible = True\n\n    def _update_popup(self) -> None:\n        mdpopups.update_popup(self.view,\n                              self._build_popup_content(),\n                              css=popup_css,\n                              md=True,\n                              wrapper_class=popup_class)\n\n    def _build_popup_content(self) -> str:\n        if settings.highlight_active_signature_parameter:\n            return self._build_popup_content_style_vscode()\n        else:\n            # Default to \"sublime\".\n            return self._build_popup_content_style_sublime()\n\n    def _view_language(self, view: sublime.View, config_name: str) -> 'Optional[str]':\n        languages = view.settings().get('lsp_language')\n        return languages.get(config_name) if languages else None\n\n    def _on_hide(self):\n        self._visible = False\n\n    def _on_hover_navigate(self, href):\n        webbrowser.open_new_tab(href)\n\n    def _build_overload_selector(self) -> str:\n        return \"**{}** of **{}** overloads (use the \u2191 \u2193 keys to navigate):\\n\".format(\n            str(self._active_signature + 1), str(len(self._signatures)))\n\n    def _build_popup_content_style_sublime(self) -> str:\n        signature = self._signatures[self._active_signature]\n        formatted = []\n\n        if len(self._signatures) > 1:\n            formatted.append(self._build_overload_selector())\n\n        signature_label = signature.get('label')\n        if len(signature_label) > 400:\n            label = \"```{} ...```\".format(signature_label[0:400])  # long code blocks = hangs\n        else:\n            label = \"```{}\\n{}\\n```\\n\".format(self._language_id, signature_label)\n        formatted.append(label)\n\n        params = signature.get('parameters')\n        if params:\n            for parameter in params:\n                paramDocs = parameter.get('documentation', None)\n                if paramDocs:\n                    formatted.append(\"**{}**\\n\".format(parameter.get('label')))\n                    formatted.append(\"* *{}*\\n\".format(paramDocs))\n        sigDocs = signature.get('documentation', None)\n        if sigDocs:\n            formatted.append(sigDocs)\n        return \"\\n\".join(formatted)\n\n    def _build_popup_content_style_vscode(self) -> str:\n        # Fetch all the relevant data.\n        signature_label = \"\"\n        signature_documentation = \"\"\n        parameter_label = \"\"\n        parameter_documentation = \"\"\n        if self._active_signature in range(0, len(self._signatures)):\n            signature = self._signatures[self._active_signature]\n            signature_label = html.escape(signature[\"label\"], quote=False)\n            signature_documentation = signature.get(\"documentation\", \"\")  # Optional.\n            parameters = signature.get(\"parameters\", None)\n            if parameters and self._active_parameter in range(0, len(parameters)):\n                parameter = parameters[self._active_parameter]\n                parameter_label = html.escape(parameter[\"label\"], quote=False)\n                parameter_documentation = parameter.get(\"documentation\", \"\")  # Optional.\n\n        formatted = []\n\n        if len(self._signatures) > 1:\n            formatted.append(self._build_overload_selector())\n\n        # Write the active signature and give special treatment to the active parameter (if found).\n        # Note that this <div> class and the extra <pre> are copied from mdpopups' HTML output. When mdpopups changes\n        # its output style, we must update this literal string accordingly.\n        formatted.append('<div class=\"highlight\"><pre>')\n        if parameter_label:\n            signature_label = self._replace_active_parameter(signature_label, parameter_label)\n        formatted.append(signature_label)\n        formatted.append(\"</pre></div>\")\n\n        if parameter_documentation:\n            formatted.append(parameter_documentation)\n\n        if signature_documentation:\n            formatted.append(signature_documentation)\n\n        return \"\\n\".join(formatted)\n\n    def _replace_active_parameter(self, signature: str, parameter: str) -> str:\n        if parameter[0].isalnum() and parameter[-1].isalnum():\n            pattern = r'\\b{}\\b'.format(re.escape(parameter))\n        else:\n            # If the left or right boundary of the parameter string is not an alphanumeric character, the \\b check will\n            # never match. In this case, it's probably safe to assume the parameter string itself will be a good pattern\n            # to search for.\n            pattern = re.escape(parameter)\n        replacement = '<span style=\"font-weight: bold; text-decoration: underline\">{}</span>'.format(parameter)\n        # FIXME: This is somewhat language-specific to look for an opening parenthesis. Most languages use parentheses\n        # for their parameter lists though.\n        start_of_param_list_pos = signature.find('(')\n        # Note that this works even when we don't find an opening parenthesis, because .find returns -1 in that case.\n        start_of_param_list = signature[start_of_param_list_pos + 1:]\n        return signature[:start_of_param_list_pos + 1] + re.sub(pattern, replacement, start_of_param_list, 1)\n", "path": "plugin/signature_help.py"}], "after_files": [{"content": "import mdpopups\nimport sublime\nimport sublime_plugin\nimport webbrowser\nimport re\nimport html\n\ntry:\n    from typing import Any, List, Dict, Optional\n    assert Any and List and Dict and Optional\nexcept ImportError:\n    pass\n\nfrom .core.configurations import is_supported_syntax\nfrom .core.registry import config_for_scope, session_for_view, client_for_view\nfrom .core.documents import get_document_position\nfrom .core.events import global_events\nfrom .core.protocol import Request\nfrom .core.logging import debug\nfrom .core.popups import popup_css, popup_class\nfrom .core.settings import settings\n\n\ndef get_documentation(d: 'Dict[str, Any]') -> 'Optional[str]':\n    docs = d.get('documentation', None)\n    if docs is None:\n        return None\n    elif isinstance(docs, str):\n        # In older version of the protocol, documentation was just a string.\n        return docs\n    elif isinstance(docs, dict):\n        # This can be either \"plaintext\" or \"markdown\" format. For now, we can dump it into the popup box. It would\n        # be nice to handle the markdown in a special way.\n        return docs.get('value', None)\n    else:\n        debug('unknown documentation type:', str(d))\n        return None\n\n\nclass SignatureHelpListener(sublime_plugin.ViewEventListener):\n\n    def __init__(self, view):\n        self.view = view\n        self._initialized = False\n        self._signature_help_triggers = []  # type: List[str]\n        self._visible = False\n        self._language_id = \"\"\n        self._signatures = []  # type: List[Any]\n        self._active_signature = -1\n        self._active_parameter = -1\n\n    @classmethod\n    def is_applicable(cls, settings):\n        syntax = settings.get('syntax')\n        return syntax and is_supported_syntax(syntax)\n\n    def initialize(self):\n        session = session_for_view(self.view)\n        if session:\n            signatureHelpProvider = session.get_capability(\n                'signatureHelpProvider')\n            if signatureHelpProvider:\n                self._signature_help_triggers = signatureHelpProvider.get(\n                    'triggerCharacters')\n\n        config = config_for_scope(self.view)\n        if config:\n            self._language_id = self._view_language(self.view, config.name)\n\n        self._initialized = True\n\n    def on_modified_async(self):\n        pos = self.view.sel()[0].begin()\n        # TODO: this will fire too often, narrow down using scopes or regex\n        if not self._initialized:\n            self.initialize()\n\n        if self._signature_help_triggers:\n            last_char = self.view.substr(pos - 1)\n            if last_char in self._signature_help_triggers:\n                self.request_signature_help(pos)\n            elif self._visible:\n                if last_char.isspace():\n                    # Peek behind to find the last non-whitespace character.\n                    last_char = self.view.substr(self.view.find_by_class(pos, False, ~0) - 1)\n                if last_char not in self._signature_help_triggers:\n                    self.view.hide_popup()\n\n    def request_signature_help(self, point) -> None:\n        client = client_for_view(self.view)\n        if client:\n            global_events.publish(\"view.on_purge_changes\", self.view)\n            document_position = get_document_position(self.view, point)\n            if document_position:\n                client.send_request(\n                    Request.signatureHelp(document_position),\n                    lambda response: self.handle_response(response, point))\n\n    def handle_response(self, response: 'Optional[Dict]', point) -> None:\n        if response is not None:\n            self._signatures = response.get(\"signatures\", [])\n            self._active_signature = response.get(\"activeSignature\", -1)\n            self._active_parameter = response.get(\"activeParameter\", -1)\n\n            if self._signatures:\n                if not 0 <= self._active_signature < len(self._signatures):\n                    debug(\"activeSignature {} not a valid index for signatures length {}\".format(\n                        self._active_signature, len(self._signatures)))\n                    self._active_signature = 0\n            else:\n                if self._active_signature != -1:\n                    debug(\"activeSignature should be -1 or null when no signatures are returned\")\n                    self._active_signature = -1\n\n            if len(self._signatures) > 0:\n                if self._visible:\n                    self._update_popup()\n                else:\n                    self._show_popup(point)\n\n    def on_query_context(self, key, _, operand, __):\n        if key != \"lsp.signature_help\":\n            return False  # Let someone else handle this keybinding.\n        elif not self._visible:\n            if operand == 0:\n                self.request_signature_help(self.view.sel()[0].begin())\n                return True\n            else:\n                return False  # Let someone else handle this keybinding.\n        elif len(self._signatures) < 2:\n            return False  # Let someone else handle this keybinding.\n        else:\n            # We use the \"operand\" for the number -1 or +1. See the keybindings.\n            new_index = self._active_signature + operand\n\n            # clamp signature index\n            new_index = max(0, min(new_index, len(self._signatures) - 1))\n\n            # only update when changed\n            if new_index != self._active_signature:\n                self._active_signature = new_index\n                self._update_popup()\n\n            return True  # We handled this keybinding.\n\n    def _show_popup(self, point: int) -> None:\n        mdpopups.show_popup(self.view,\n                            self._build_popup_content(),\n                            css=popup_css,\n                            md=True,\n                            flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,\n                            location=point,\n                            wrapper_class=popup_class,\n                            max_width=800,\n                            on_hide=self._on_hide,\n                            on_navigate=self._on_hover_navigate)\n        self._visible = True\n\n    def _update_popup(self) -> None:\n        mdpopups.update_popup(self.view,\n                              self._build_popup_content(),\n                              css=popup_css,\n                              md=True,\n                              wrapper_class=popup_class)\n\n    def _build_popup_content(self) -> str:\n        if settings.highlight_active_signature_parameter:\n            return self._build_popup_content_style_vscode()\n        else:\n            # Default to \"sublime\".\n            return self._build_popup_content_style_sublime()\n\n    def _view_language(self, view: sublime.View, config_name: str) -> 'Optional[str]':\n        languages = view.settings().get('lsp_language')\n        return languages.get(config_name) if languages else None\n\n    def _on_hide(self):\n        self._visible = False\n\n    def _on_hover_navigate(self, href):\n        webbrowser.open_new_tab(href)\n\n    def _build_overload_selector(self) -> str:\n        return \"**{}** of **{}** overloads (use the \u2191 \u2193 keys to navigate):\\n\".format(\n            str(self._active_signature + 1), str(len(self._signatures)))\n\n    def _build_popup_content_style_sublime(self) -> str:\n        signature = self._signatures[self._active_signature]\n        formatted = []\n\n        if len(self._signatures) > 1:\n            formatted.append(self._build_overload_selector())\n\n        signature_label = signature.get('label')\n        if len(signature_label) > 400:\n            label = \"```{} ...```\".format(signature_label[0:400])  # long code blocks = hangs\n        else:\n            label = \"```{}\\n{}\\n```\\n\".format(self._language_id, signature_label)\n        formatted.append(label)\n\n        params = signature.get('parameters')\n        if params:\n            for parameter in params:\n                param_docs = get_documentation(parameter)\n                if param_docs:\n                    formatted.append(\"**{}**\\n\".format(parameter.get('label')))\n                    formatted.append(\"* *{}*\\n\".format(param_docs))\n        sigDocs = signature.get('documentation', None)\n        if sigDocs:\n            formatted.append(sigDocs)\n        return \"\\n\".join(formatted)\n\n    def _build_popup_content_style_vscode(self) -> str:\n        # Fetch all the relevant data.\n        signature_label = \"\"\n        signature_documentation = \"\"  # type: Optional[str]\n        parameter_label = \"\"\n        parameter_documentation = \"\"  # type: Optional[str]\n        if self._active_signature in range(0, len(self._signatures)):\n            signature = self._signatures[self._active_signature]\n            signature_label = html.escape(signature[\"label\"], quote=False)\n            signature_documentation = get_documentation(signature)\n            parameters = signature.get(\"parameters\", None)\n            if parameters and self._active_parameter in range(0, len(parameters)):\n                parameter = parameters[self._active_parameter]\n                parameter_label = html.escape(parameter[\"label\"], quote=False)\n                parameter_documentation = get_documentation(parameter)\n\n        formatted = []\n\n        if len(self._signatures) > 1:\n            formatted.append(self._build_overload_selector())\n\n        # Write the active signature and give special treatment to the active parameter (if found).\n        # Note that this <div> class and the extra <pre> are copied from mdpopups' HTML output. When mdpopups changes\n        # its output style, we must update this literal string accordingly.\n        formatted.append('<div class=\"highlight\"><pre>')\n        if parameter_label:\n            signature_label = self._replace_active_parameter(signature_label, parameter_label)\n        formatted.append(signature_label)\n        formatted.append(\"</pre></div>\")\n\n        if parameter_documentation:\n            formatted.append(parameter_documentation)\n\n        if signature_documentation:\n            formatted.append(signature_documentation)\n\n        return \"\\n\".join(formatted)\n\n    def _replace_active_parameter(self, signature: str, parameter: str) -> str:\n        if parameter[0].isalnum() and parameter[-1].isalnum():\n            pattern = r'\\b{}\\b'.format(re.escape(parameter))\n        else:\n            # If the left or right boundary of the parameter string is not an alphanumeric character, the \\b check will\n            # never match. In this case, it's probably safe to assume the parameter string itself will be a good pattern\n            # to search for.\n            pattern = re.escape(parameter)\n        replacement = '<span style=\"font-weight: bold; text-decoration: underline\">{}</span>'.format(parameter)\n        # FIXME: This is somewhat language-specific to look for an opening parenthesis. Most languages use parentheses\n        # for their parameter lists though.\n        start_of_param_list_pos = signature.find('(')\n        # Note that this works even when we don't find an opening parenthesis, because .find returns -1 in that case.\n        start_of_param_list = signature[start_of_param_list_pos + 1:]\n        return signature[:start_of_param_list_pos + 1] + re.sub(pattern, replacement, start_of_param_list, 1)\n", "path": "plugin/signature_help.py"}]}