We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Keep using trigger characters, or start using selectors?
For some reason the final `commit_completion` command re-triggers the completion panel "forever". I need to `esc` to hide it.

![Animation](https://user-images.githubusercontent.com/16542113/77469677-bea0de80-6e0f-11ea-995c-868676cf6f2b.png)

Settings are

```
	"auto_complete": true,
	"auto_complete_commit_on_tab": true,
	"auto_complete_with_fields": true,
```

_Originally posted by @deathaxe in https://github.com/sublimelsp/LSP/pull/866#issuecomment-603466761_

--- 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/completion.py`
Content:
```
1 import sublime
2 import sublime_plugin
3 
4 from .core.configurations import is_supported_syntax
5 from .core.edit import parse_text_edit
6 from .core.logging import debug
7 from .core.protocol import Request, Range, InsertTextFormat
8 from .core.registry import session_for_view, client_from_session, LSPViewEventListener
9 from .core.sessions import Session
10 from .core.settings import settings, client_configs
11 from .core.typing import Any, List, Dict, Optional, Union
12 from .core.views import range_to_region
13 from .core.views import text_document_position_params
14 
15 
16 completion_kinds = {
17     1: (sublime.KIND_ID_MARKUP, "Ξ", "Text"),
18     2: (sublime.KIND_ID_FUNCTION, "λ", "Method"),
19     3: (sublime.KIND_ID_FUNCTION, "λ", "Function"),
20     4: (sublime.KIND_ID_FUNCTION, "c", "Constructor"),
21     5: (sublime.KIND_ID_VARIABLE, "f", "Field"),
22     6: (sublime.KIND_ID_VARIABLE, "v", "Variable"),
23     7: (sublime.KIND_ID_TYPE, "c", "Class"),
24     8: (sublime.KIND_ID_TYPE, "i", "Interface"),
25     9: (sublime.KIND_ID_NAMESPACE, "◪", "Module"),
26     10: (sublime.KIND_ID_VARIABLE, "ρ", "Property"),
27     11: (sublime.KIND_ID_VARIABLE, "u", "Unit"),
28     12: (sublime.KIND_ID_VARIABLE, "ν", "Value"),
29     13: (sublime.KIND_ID_TYPE, "ε", "Enum"),
30     14: (sublime.KIND_ID_KEYWORD, "κ", "Keyword"),
31     15: (sublime.KIND_ID_SNIPPET, "s", "Snippet"),
32     16: (sublime.KIND_ID_AMBIGUOUS, "c", "Color"),
33     17: (sublime.KIND_ID_AMBIGUOUS, "#", "File"),
34     18: (sublime.KIND_ID_AMBIGUOUS, "⇢", "Reference"),
35     19: (sublime.KIND_ID_AMBIGUOUS, "ƒ", "Folder"),
36     20: (sublime.KIND_ID_TYPE, "ε", "EnumMember"),
37     21: (sublime.KIND_ID_VARIABLE, "π", "Constant"),
38     22: (sublime.KIND_ID_TYPE, "s", "Struct"),
39     23: (sublime.KIND_ID_FUNCTION, "e", "Event"),
40     24: (sublime.KIND_ID_KEYWORD, "ο", "Operator"),
41     25: (sublime.KIND_ID_TYPE, "τ", "Type Parameter")
42 }
43 
44 
45 def format_completion(item: dict, change_id: Any) -> sublime.CompletionItem:
46     item_kind = item.get("kind")
47     if item_kind:
48         kind = completion_kinds.get(item_kind, sublime.KIND_AMBIGUOUS)
49     else:
50         kind = sublime.KIND_AMBIGUOUS
51 
52     if item.get("deprecated", False):
53         kind = (kind[0], '⚠', "⚠ {} - Deprecated".format(kind[2]))
54 
55     item["change_id"] = change_id
56 
57     return sublime.CompletionItem.command_completion(
58         trigger=item["label"],
59         command="lsp_select_completion_item",
60         args=item,
61         annotation=item.get('detail') or "",
62         kind=kind
63     )
64 
65 
66 class LspSelectCompletionItemCommand(sublime_plugin.TextCommand):
67     """
68     This command must handle four different kinds of LSP completion items:
69 
70     1) plaintext + insertText   (e.g. pyls)
71     2) plaintext + textEdit     (e.g. intelephense)
72     3) snippet   + insertText   (???)
73     4) snippet   + textEdit     (e.g. clangd, intelephense)
74 
75     For cases (3) and (4) we are forced to use the "insert_snippet" command.
76     """
77 
78     def run(self, edit: sublime.Edit, **item: Any) -> None:
79         # Is it a textEdit or an insertText?
80         text_edit = item.get('textEdit')
81         if text_edit:
82             new_text = text_edit['newText']
83             # this region was valid a few view.change_count() moments back ...
84             edit_region = range_to_region(Range.from_lsp(text_edit['range']), self.view)
85             # ... but this brings it to the present.
86             edit_region = self.view.transform_region_from(edit_region, item["change_id"])
87             selection = self.view.sel()
88             primary_cursor_position = selection[0].b
89             for region in reversed(selection):
90                 # For each selection region, apply the same removal as for the "primary" region.
91                 # To do that, translate, or offset, the LSP edit region into the non-"primary" regions.
92                 # The concept of "primary" is our own, and there is no mention of it in the LSP spec.
93                 translation = region.b - primary_cursor_position
94                 self.view.erase(edit, sublime.Region(edit_region.a + translation, edit_region.b + translation))
95         else:
96             new_text = item.get('insertText') or item['label']
97 
98         # Is it a plaintext or a snippet?
99         if item.get("insertTextFormat", InsertTextFormat.PlainText) == InsertTextFormat.Snippet:
100             self.view.run_command("insert_snippet", {"contents": new_text})
101         else:
102             self.view.run_command("insert", {"characters": new_text})
103 
104         # import statements, etc. some servers only return these after a resolve.
105         additional_edits = item.get('additionalTextEdits')
106         if additional_edits:
107             self.apply_additional_edits(additional_edits)
108         else:
109             self.do_resolve(item)
110 
111     def do_resolve(self, item: dict) -> None:
112         session = session_for_view(self.view, 'completionProvider', self.view.sel()[0].begin())
113         if not session:
114             return
115 
116         client = client_from_session(session)
117         if not client:
118             return
119 
120         completion_provider = session.get_capability('completionProvider')
121         has_resolve_provider = completion_provider and completion_provider.get('resolveProvider', False)
122         if has_resolve_provider:
123             client.send_request(Request.resolveCompletionItem(item), self.handle_resolve_response)
124 
125     def handle_resolve_response(self, response: Optional[dict]) -> None:
126         if response:
127             additional_edits = response.get('additionalTextEdits')
128             if additional_edits:
129                 self.apply_additional_edits(additional_edits)
130 
131     def apply_additional_edits(self, additional_edits: List[dict]) -> None:
132         edits = list(parse_text_edit(additional_edit) for additional_edit in additional_edits)
133         debug('applying additional edits:', edits)
134         self.view.run_command("lsp_apply_document_edit", {'changes': edits})
135         sublime.status_message('Applied additional edits for completion')
136 
137 
138 def resolve(completion_list: sublime.CompletionList, items: List[sublime.CompletionItem], flags: int = 0) -> None:
139     # Resolve the promise on the main thread to prevent any sort of data race for _set_target (see sublime_plugin.py).
140     sublime.set_timeout(lambda: completion_list.set_completions(items, flags))
141 
142 
143 class CompletionHandler(LSPViewEventListener):
144     def __init__(self, view: sublime.View) -> None:
145         super().__init__(view)
146         self.initialized = False
147         self.enabled = False
148 
149     @classmethod
150     def is_applicable(cls, view_settings: dict) -> bool:
151         if 'completion' in settings.disabled_capabilities:
152             return False
153 
154         syntax = view_settings.get('syntax')
155         return is_supported_syntax(syntax, client_configs.all) if syntax else False
156 
157     def initialize(self) -> None:
158         self.initialized = True
159         session = session_for_view(self.view, 'completionProvider')
160         if session:
161             completionProvider = session.get_capability('completionProvider') or dict()  # type: dict
162             # A language server may have an empty dict as CompletionOptions. In that case,
163             # no trigger characters will be registered but we'll still respond to Sublime's
164             # usual query for completions. So the explicit check for None is necessary.
165             self.enabled = True
166 
167             trigger_chars = completionProvider.get(
168                 'triggerCharacters') or []
169             if trigger_chars:
170                 self.register_trigger_chars(session, trigger_chars)
171             # This is to make ST match with labels that have a weird prefix like a space character.
172             self.view.settings().set("auto_complete_preserve_order", "none")
173 
174     def _view_language(self, config_name: str) -> Optional[str]:
175         languages = self.view.settings().get('lsp_language')
176         return languages.get(config_name) if languages else None
177 
178     def register_trigger_chars(self, session: Session, trigger_chars: List[str]) -> None:
179         completion_triggers = self.view.settings().get('auto_complete_triggers', []) or []  # type: List[Dict[str, str]]
180         view_language = self._view_language(session.config.name)
181         if view_language:
182             for language in session.config.languages:
183                 if language.id == view_language:
184                     for scope in language.scopes:
185                         # debug("registering", trigger_chars, "for", scope)
186                         scope_trigger = next(
187                             (trigger for trigger in completion_triggers if trigger.get('selector', None) == scope),
188                             None
189                         )
190                         if not scope_trigger:  # do not override user's trigger settings.
191                             completion_triggers.append({
192                                 'characters': "".join(trigger_chars),
193                                 'selector': scope
194                             })
195 
196             self.view.settings().set('auto_complete_triggers', completion_triggers)
197 
198     def on_query_completions(self, prefix: str, locations: List[int]) -> Optional[sublime.CompletionList]:
199         if not self.initialized:
200             self.initialize()
201         if not self.enabled:
202             return None
203         client = client_from_session(session_for_view(self.view, 'completionProvider', locations[0]))
204         if not client:
205             return None
206         self.manager.documents.purge_changes(self.view)
207         completion_list = sublime.CompletionList()
208         client.send_request(
209             Request.complete(text_document_position_params(self.view, locations[0])),
210             lambda res: self.handle_response(res, completion_list, self.view.change_id()),
211             lambda res: self.handle_error(res, completion_list))
212         return completion_list
213 
214     def handle_response(self, response: Optional[Union[dict, List]],
215                         completion_list: sublime.CompletionList, change_id: Any) -> None:
216         response_items = []  # type: List[Dict]
217         incomplete = False
218         if isinstance(response, dict):
219             response_items = response["items"] or []
220             incomplete = response.get("isIncomplete", False)
221         elif isinstance(response, list):
222             response_items = response
223         response_items = sorted(response_items, key=lambda item: item.get("sortText") or item["label"])
224 
225         flags = 0
226         if settings.only_show_lsp_completions:
227             flags |= sublime.INHIBIT_WORD_COMPLETIONS
228             flags |= sublime.INHIBIT_EXPLICIT_COMPLETIONS
229 
230         if incomplete:
231             flags |= sublime.DYNAMIC_COMPLETIONS
232         resolve(completion_list, [format_completion(i, change_id) for i in response_items], flags)
233 
234     def handle_error(self, error: dict, completion_list: sublime.CompletionList) -> None:
235         resolve(completion_list, [])
236         sublime.status_message('Completion error: ' + str(error.get('message')))
237
```
--- 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/completion.py b/plugin/completion.py
--- a/plugin/completion.py
+++ b/plugin/completion.py
@@ -171,29 +171,15 @@
             # This is to make ST match with labels that have a weird prefix like a space character.
             self.view.settings().set("auto_complete_preserve_order", "none")
 
-    def _view_language(self, config_name: str) -> Optional[str]:
-        languages = self.view.settings().get('lsp_language')
-        return languages.get(config_name) if languages else None
-
     def register_trigger_chars(self, session: Session, trigger_chars: List[str]) -> None:
-        completion_triggers = self.view.settings().get('auto_complete_triggers', []) or []  # type: List[Dict[str, str]]
-        view_language = self._view_language(session.config.name)
-        if view_language:
-            for language in session.config.languages:
-                if language.id == view_language:
-                    for scope in language.scopes:
-                        # debug("registering", trigger_chars, "for", scope)
-                        scope_trigger = next(
-                            (trigger for trigger in completion_triggers if trigger.get('selector', None) == scope),
-                            None
-                        )
-                        if not scope_trigger:  # do not override user's trigger settings.
-                            completion_triggers.append({
-                                'characters': "".join(trigger_chars),
-                                'selector': scope
-                            })
-
-            self.view.settings().set('auto_complete_triggers', completion_triggers)
+        completion_triggers = self.view.settings().get('auto_complete_triggers') or []  # type: List[Dict[str, str]]
+
+        completion_triggers.append({
+            'characters': "".join(trigger_chars),
+            'selector': "- comment - punctuation.definition.string.end"
+        })
+
+        self.view.settings().set('auto_complete_triggers', completion_triggers)
 
     def on_query_completions(self, prefix: str, locations: List[int]) -> Optional[sublime.CompletionList]:
         if not self.initialized:

{"golden_diff": "diff --git a/plugin/completion.py b/plugin/completion.py\n--- a/plugin/completion.py\n+++ b/plugin/completion.py\n@@ -171,29 +171,15 @@\n             # This is to make ST match with labels that have a weird prefix like a space character.\n             self.view.settings().set(\"auto_complete_preserve_order\", \"none\")\n \n-    def _view_language(self, config_name: str) -> Optional[str]:\n-        languages = self.view.settings().get('lsp_language')\n-        return languages.get(config_name) if languages else None\n-\n     def register_trigger_chars(self, session: Session, trigger_chars: List[str]) -> None:\n-        completion_triggers = self.view.settings().get('auto_complete_triggers', []) or []  # type: List[Dict[str, str]]\n-        view_language = self._view_language(session.config.name)\n-        if view_language:\n-            for language in session.config.languages:\n-                if language.id == view_language:\n-                    for scope in language.scopes:\n-                        # debug(\"registering\", trigger_chars, \"for\", scope)\n-                        scope_trigger = next(\n-                            (trigger for trigger in completion_triggers if trigger.get('selector', None) == scope),\n-                            None\n-                        )\n-                        if not scope_trigger:  # do not override user's trigger settings.\n-                            completion_triggers.append({\n-                                'characters': \"\".join(trigger_chars),\n-                                'selector': scope\n-                            })\n-\n-            self.view.settings().set('auto_complete_triggers', completion_triggers)\n+        completion_triggers = self.view.settings().get('auto_complete_triggers') or []  # type: List[Dict[str, str]]\n+\n+        completion_triggers.append({\n+            'characters': \"\".join(trigger_chars),\n+            'selector': \"- comment - punctuation.definition.string.end\"\n+        })\n+\n+        self.view.settings().set('auto_complete_triggers', completion_triggers)\n \n     def on_query_completions(self, prefix: str, locations: List[int]) -> Optional[sublime.CompletionList]:\n         if not self.initialized:\n", "issue": "Keep using trigger characters, or start using selectors?\nFor some reason the final `commit_completion` command re-triggers the completion panel \"forever\". I need to `esc` to hide it.\r\n\r\n![Animation](https://user-images.githubusercontent.com/16542113/77469677-bea0de80-6e0f-11ea-995c-868676cf6f2b.png)\r\n\r\nSettings are\r\n\r\n```\r\n\t\"auto_complete\": true,\r\n\t\"auto_complete_commit_on_tab\": true,\r\n\t\"auto_complete_with_fields\": true,\r\n```\r\n\r\n_Originally posted by @deathaxe in https://github.com/sublimelsp/LSP/pull/866#issuecomment-603466761_\n", "before_files": [{"content": "import sublime\nimport sublime_plugin\n\nfrom .core.configurations import is_supported_syntax\nfrom .core.edit import parse_text_edit\nfrom .core.logging import debug\nfrom .core.protocol import Request, Range, InsertTextFormat\nfrom .core.registry import session_for_view, client_from_session, LSPViewEventListener\nfrom .core.sessions import Session\nfrom .core.settings import settings, client_configs\nfrom .core.typing import Any, List, Dict, Optional, Union\nfrom .core.views import range_to_region\nfrom .core.views import text_document_position_params\n\n\ncompletion_kinds = {\n    1: (sublime.KIND_ID_MARKUP, \"\u039e\", \"Text\"),\n    2: (sublime.KIND_ID_FUNCTION, \"\u03bb\", \"Method\"),\n    3: (sublime.KIND_ID_FUNCTION, \"\u03bb\", \"Function\"),\n    4: (sublime.KIND_ID_FUNCTION, \"c\", \"Constructor\"),\n    5: (sublime.KIND_ID_VARIABLE, \"f\", \"Field\"),\n    6: (sublime.KIND_ID_VARIABLE, \"v\", \"Variable\"),\n    7: (sublime.KIND_ID_TYPE, \"c\", \"Class\"),\n    8: (sublime.KIND_ID_TYPE, \"i\", \"Interface\"),\n    9: (sublime.KIND_ID_NAMESPACE, \"\u25ea\", \"Module\"),\n    10: (sublime.KIND_ID_VARIABLE, \"\u03c1\", \"Property\"),\n    11: (sublime.KIND_ID_VARIABLE, \"u\", \"Unit\"),\n    12: (sublime.KIND_ID_VARIABLE, \"\u03bd\", \"Value\"),\n    13: (sublime.KIND_ID_TYPE, \"\u03b5\", \"Enum\"),\n    14: (sublime.KIND_ID_KEYWORD, \"\u03ba\", \"Keyword\"),\n    15: (sublime.KIND_ID_SNIPPET, \"s\", \"Snippet\"),\n    16: (sublime.KIND_ID_AMBIGUOUS, \"c\", \"Color\"),\n    17: (sublime.KIND_ID_AMBIGUOUS, \"#\", \"File\"),\n    18: (sublime.KIND_ID_AMBIGUOUS, \"\u21e2\", \"Reference\"),\n    19: (sublime.KIND_ID_AMBIGUOUS, \"\u0192\", \"Folder\"),\n    20: (sublime.KIND_ID_TYPE, \"\u03b5\", \"EnumMember\"),\n    21: (sublime.KIND_ID_VARIABLE, \"\u03c0\", \"Constant\"),\n    22: (sublime.KIND_ID_TYPE, \"s\", \"Struct\"),\n    23: (sublime.KIND_ID_FUNCTION, \"e\", \"Event\"),\n    24: (sublime.KIND_ID_KEYWORD, \"\u03bf\", \"Operator\"),\n    25: (sublime.KIND_ID_TYPE, \"\u03c4\", \"Type Parameter\")\n}\n\n\ndef format_completion(item: dict, change_id: Any) -> sublime.CompletionItem:\n    item_kind = item.get(\"kind\")\n    if item_kind:\n        kind = completion_kinds.get(item_kind, sublime.KIND_AMBIGUOUS)\n    else:\n        kind = sublime.KIND_AMBIGUOUS\n\n    if item.get(\"deprecated\", False):\n        kind = (kind[0], '\u26a0', \"\u26a0 {} - Deprecated\".format(kind[2]))\n\n    item[\"change_id\"] = change_id\n\n    return sublime.CompletionItem.command_completion(\n        trigger=item[\"label\"],\n        command=\"lsp_select_completion_item\",\n        args=item,\n        annotation=item.get('detail') or \"\",\n        kind=kind\n    )\n\n\nclass LspSelectCompletionItemCommand(sublime_plugin.TextCommand):\n    \"\"\"\n    This command must handle four different kinds of LSP completion items:\n\n    1) plaintext + insertText   (e.g. pyls)\n    2) plaintext + textEdit     (e.g. intelephense)\n    3) snippet   + insertText   (???)\n    4) snippet   + textEdit     (e.g. clangd, intelephense)\n\n    For cases (3) and (4) we are forced to use the \"insert_snippet\" command.\n    \"\"\"\n\n    def run(self, edit: sublime.Edit, **item: Any) -> None:\n        # Is it a textEdit or an insertText?\n        text_edit = item.get('textEdit')\n        if text_edit:\n            new_text = text_edit['newText']\n            # this region was valid a few view.change_count() moments back ...\n            edit_region = range_to_region(Range.from_lsp(text_edit['range']), self.view)\n            # ... but this brings it to the present.\n            edit_region = self.view.transform_region_from(edit_region, item[\"change_id\"])\n            selection = self.view.sel()\n            primary_cursor_position = selection[0].b\n            for region in reversed(selection):\n                # For each selection region, apply the same removal as for the \"primary\" region.\n                # To do that, translate, or offset, the LSP edit region into the non-\"primary\" regions.\n                # The concept of \"primary\" is our own, and there is no mention of it in the LSP spec.\n                translation = region.b - primary_cursor_position\n                self.view.erase(edit, sublime.Region(edit_region.a + translation, edit_region.b + translation))\n        else:\n            new_text = item.get('insertText') or item['label']\n\n        # Is it a plaintext or a snippet?\n        if item.get(\"insertTextFormat\", InsertTextFormat.PlainText) == InsertTextFormat.Snippet:\n            self.view.run_command(\"insert_snippet\", {\"contents\": new_text})\n        else:\n            self.view.run_command(\"insert\", {\"characters\": new_text})\n\n        # import statements, etc. some servers only return these after a resolve.\n        additional_edits = item.get('additionalTextEdits')\n        if additional_edits:\n            self.apply_additional_edits(additional_edits)\n        else:\n            self.do_resolve(item)\n\n    def do_resolve(self, item: dict) -> None:\n        session = session_for_view(self.view, 'completionProvider', self.view.sel()[0].begin())\n        if not session:\n            return\n\n        client = client_from_session(session)\n        if not client:\n            return\n\n        completion_provider = session.get_capability('completionProvider')\n        has_resolve_provider = completion_provider and completion_provider.get('resolveProvider', False)\n        if has_resolve_provider:\n            client.send_request(Request.resolveCompletionItem(item), self.handle_resolve_response)\n\n    def handle_resolve_response(self, response: Optional[dict]) -> None:\n        if response:\n            additional_edits = response.get('additionalTextEdits')\n            if additional_edits:\n                self.apply_additional_edits(additional_edits)\n\n    def apply_additional_edits(self, additional_edits: List[dict]) -> None:\n        edits = list(parse_text_edit(additional_edit) for additional_edit in additional_edits)\n        debug('applying additional edits:', edits)\n        self.view.run_command(\"lsp_apply_document_edit\", {'changes': edits})\n        sublime.status_message('Applied additional edits for completion')\n\n\ndef resolve(completion_list: sublime.CompletionList, items: List[sublime.CompletionItem], flags: int = 0) -> None:\n    # Resolve the promise on the main thread to prevent any sort of data race for _set_target (see sublime_plugin.py).\n    sublime.set_timeout(lambda: completion_list.set_completions(items, flags))\n\n\nclass CompletionHandler(LSPViewEventListener):\n    def __init__(self, view: sublime.View) -> None:\n        super().__init__(view)\n        self.initialized = False\n        self.enabled = False\n\n    @classmethod\n    def is_applicable(cls, view_settings: dict) -> bool:\n        if 'completion' in settings.disabled_capabilities:\n            return False\n\n        syntax = view_settings.get('syntax')\n        return is_supported_syntax(syntax, client_configs.all) if syntax else False\n\n    def initialize(self) -> None:\n        self.initialized = True\n        session = session_for_view(self.view, 'completionProvider')\n        if session:\n            completionProvider = session.get_capability('completionProvider') or dict()  # type: dict\n            # A language server may have an empty dict as CompletionOptions. In that case,\n            # no trigger characters will be registered but we'll still respond to Sublime's\n            # usual query for completions. So the explicit check for None is necessary.\n            self.enabled = True\n\n            trigger_chars = completionProvider.get(\n                'triggerCharacters') or []\n            if trigger_chars:\n                self.register_trigger_chars(session, trigger_chars)\n            # This is to make ST match with labels that have a weird prefix like a space character.\n            self.view.settings().set(\"auto_complete_preserve_order\", \"none\")\n\n    def _view_language(self, config_name: str) -> Optional[str]:\n        languages = self.view.settings().get('lsp_language')\n        return languages.get(config_name) if languages else None\n\n    def register_trigger_chars(self, session: Session, trigger_chars: List[str]) -> None:\n        completion_triggers = self.view.settings().get('auto_complete_triggers', []) or []  # type: List[Dict[str, str]]\n        view_language = self._view_language(session.config.name)\n        if view_language:\n            for language in session.config.languages:\n                if language.id == view_language:\n                    for scope in language.scopes:\n                        # debug(\"registering\", trigger_chars, \"for\", scope)\n                        scope_trigger = next(\n                            (trigger for trigger in completion_triggers if trigger.get('selector', None) == scope),\n                            None\n                        )\n                        if not scope_trigger:  # do not override user's trigger settings.\n                            completion_triggers.append({\n                                'characters': \"\".join(trigger_chars),\n                                'selector': scope\n                            })\n\n            self.view.settings().set('auto_complete_triggers', completion_triggers)\n\n    def on_query_completions(self, prefix: str, locations: List[int]) -> Optional[sublime.CompletionList]:\n        if not self.initialized:\n            self.initialize()\n        if not self.enabled:\n            return None\n        client = client_from_session(session_for_view(self.view, 'completionProvider', locations[0]))\n        if not client:\n            return None\n        self.manager.documents.purge_changes(self.view)\n        completion_list = sublime.CompletionList()\n        client.send_request(\n            Request.complete(text_document_position_params(self.view, locations[0])),\n            lambda res: self.handle_response(res, completion_list, self.view.change_id()),\n            lambda res: self.handle_error(res, completion_list))\n        return completion_list\n\n    def handle_response(self, response: Optional[Union[dict, List]],\n                        completion_list: sublime.CompletionList, change_id: Any) -> None:\n        response_items = []  # type: List[Dict]\n        incomplete = False\n        if isinstance(response, dict):\n            response_items = response[\"items\"] or []\n            incomplete = response.get(\"isIncomplete\", False)\n        elif isinstance(response, list):\n            response_items = response\n        response_items = sorted(response_items, key=lambda item: item.get(\"sortText\") or item[\"label\"])\n\n        flags = 0\n        if settings.only_show_lsp_completions:\n            flags |= sublime.INHIBIT_WORD_COMPLETIONS\n            flags |= sublime.INHIBIT_EXPLICIT_COMPLETIONS\n\n        if incomplete:\n            flags |= sublime.DYNAMIC_COMPLETIONS\n        resolve(completion_list, [format_completion(i, change_id) for i in response_items], flags)\n\n    def handle_error(self, error: dict, completion_list: sublime.CompletionList) -> None:\n        resolve(completion_list, [])\n        sublime.status_message('Completion error: ' + str(error.get('message')))\n", "path": "plugin/completion.py"}], "after_files": [{"content": "import sublime\nimport sublime_plugin\n\nfrom .core.configurations import is_supported_syntax\nfrom .core.edit import parse_text_edit\nfrom .core.logging import debug\nfrom .core.protocol import Request, Range, InsertTextFormat\nfrom .core.registry import session_for_view, client_from_session, LSPViewEventListener\nfrom .core.sessions import Session\nfrom .core.settings import settings, client_configs\nfrom .core.typing import Any, List, Dict, Optional, Union\nfrom .core.views import range_to_region\nfrom .core.views import text_document_position_params\n\n\ncompletion_kinds = {\n    1: (sublime.KIND_ID_MARKUP, \"\u039e\", \"Text\"),\n    2: (sublime.KIND_ID_FUNCTION, \"\u03bb\", \"Method\"),\n    3: (sublime.KIND_ID_FUNCTION, \"\u03bb\", \"Function\"),\n    4: (sublime.KIND_ID_FUNCTION, \"c\", \"Constructor\"),\n    5: (sublime.KIND_ID_VARIABLE, \"f\", \"Field\"),\n    6: (sublime.KIND_ID_VARIABLE, \"v\", \"Variable\"),\n    7: (sublime.KIND_ID_TYPE, \"c\", \"Class\"),\n    8: (sublime.KIND_ID_TYPE, \"i\", \"Interface\"),\n    9: (sublime.KIND_ID_NAMESPACE, \"\u25ea\", \"Module\"),\n    10: (sublime.KIND_ID_VARIABLE, \"\u03c1\", \"Property\"),\n    11: (sublime.KIND_ID_VARIABLE, \"u\", \"Unit\"),\n    12: (sublime.KIND_ID_VARIABLE, \"\u03bd\", \"Value\"),\n    13: (sublime.KIND_ID_TYPE, \"\u03b5\", \"Enum\"),\n    14: (sublime.KIND_ID_KEYWORD, \"\u03ba\", \"Keyword\"),\n    15: (sublime.KIND_ID_SNIPPET, \"s\", \"Snippet\"),\n    16: (sublime.KIND_ID_AMBIGUOUS, \"c\", \"Color\"),\n    17: (sublime.KIND_ID_AMBIGUOUS, \"#\", \"File\"),\n    18: (sublime.KIND_ID_AMBIGUOUS, \"\u21e2\", \"Reference\"),\n    19: (sublime.KIND_ID_AMBIGUOUS, \"\u0192\", \"Folder\"),\n    20: (sublime.KIND_ID_TYPE, \"\u03b5\", \"EnumMember\"),\n    21: (sublime.KIND_ID_VARIABLE, \"\u03c0\", \"Constant\"),\n    22: (sublime.KIND_ID_TYPE, \"s\", \"Struct\"),\n    23: (sublime.KIND_ID_FUNCTION, \"e\", \"Event\"),\n    24: (sublime.KIND_ID_KEYWORD, \"\u03bf\", \"Operator\"),\n    25: (sublime.KIND_ID_TYPE, \"\u03c4\", \"Type Parameter\")\n}\n\n\ndef format_completion(item: dict, change_id: Any) -> sublime.CompletionItem:\n    item_kind = item.get(\"kind\")\n    if item_kind:\n        kind = completion_kinds.get(item_kind, sublime.KIND_AMBIGUOUS)\n    else:\n        kind = sublime.KIND_AMBIGUOUS\n\n    if item.get(\"deprecated\", False):\n        kind = (kind[0], '\u26a0', \"\u26a0 {} - Deprecated\".format(kind[2]))\n\n    item[\"change_id\"] = change_id\n\n    return sublime.CompletionItem.command_completion(\n        trigger=item[\"label\"],\n        command=\"lsp_select_completion_item\",\n        args=item,\n        annotation=item.get('detail') or \"\",\n        kind=kind\n    )\n\n\nclass LspSelectCompletionItemCommand(sublime_plugin.TextCommand):\n    \"\"\"\n    This command must handle four different kinds of LSP completion items:\n\n    1) plaintext + insertText   (e.g. pyls)\n    2) plaintext + textEdit     (e.g. intelephense)\n    3) snippet   + insertText   (???)\n    4) snippet   + textEdit     (e.g. clangd, intelephense)\n\n    For cases (3) and (4) we are forced to use the \"insert_snippet\" command.\n    \"\"\"\n\n    def run(self, edit: sublime.Edit, **item: Any) -> None:\n        # Is it a textEdit or an insertText?\n        text_edit = item.get('textEdit')\n        if text_edit:\n            new_text = text_edit['newText']\n            # this region was valid a few view.change_count() moments back ...\n            edit_region = range_to_region(Range.from_lsp(text_edit['range']), self.view)\n            # ... but this brings it to the present.\n            edit_region = self.view.transform_region_from(edit_region, item[\"change_id\"])\n            selection = self.view.sel()\n            primary_cursor_position = selection[0].b\n            for region in reversed(selection):\n                # For each selection region, apply the same removal as for the \"primary\" region.\n                # To do that, translate, or offset, the LSP edit region into the non-\"primary\" regions.\n                # The concept of \"primary\" is our own, and there is no mention of it in the LSP spec.\n                translation = region.b - primary_cursor_position\n                self.view.erase(edit, sublime.Region(edit_region.a + translation, edit_region.b + translation))\n        else:\n            new_text = item.get('insertText') or item['label']\n\n        # Is it a plaintext or a snippet?\n        if item.get(\"insertTextFormat\", InsertTextFormat.PlainText) == InsertTextFormat.Snippet:\n            self.view.run_command(\"insert_snippet\", {\"contents\": new_text})\n        else:\n            self.view.run_command(\"insert\", {\"characters\": new_text})\n\n        # import statements, etc. some servers only return these after a resolve.\n        additional_edits = item.get('additionalTextEdits')\n        if additional_edits:\n            self.apply_additional_edits(additional_edits)\n        else:\n            self.do_resolve(item)\n\n    def do_resolve(self, item: dict) -> None:\n        session = session_for_view(self.view, 'completionProvider', self.view.sel()[0].begin())\n        if not session:\n            return\n\n        client = client_from_session(session)\n        if not client:\n            return\n\n        completion_provider = session.get_capability('completionProvider')\n        has_resolve_provider = completion_provider and completion_provider.get('resolveProvider', False)\n        if has_resolve_provider:\n            client.send_request(Request.resolveCompletionItem(item), self.handle_resolve_response)\n\n    def handle_resolve_response(self, response: Optional[dict]) -> None:\n        if response:\n            additional_edits = response.get('additionalTextEdits')\n            if additional_edits:\n                self.apply_additional_edits(additional_edits)\n\n    def apply_additional_edits(self, additional_edits: List[dict]) -> None:\n        edits = list(parse_text_edit(additional_edit) for additional_edit in additional_edits)\n        debug('applying additional edits:', edits)\n        self.view.run_command(\"lsp_apply_document_edit\", {'changes': edits})\n        sublime.status_message('Applied additional edits for completion')\n\n\ndef resolve(completion_list: sublime.CompletionList, items: List[sublime.CompletionItem], flags: int = 0) -> None:\n    # Resolve the promise on the main thread to prevent any sort of data race for _set_target (see sublime_plugin.py).\n    sublime.set_timeout(lambda: completion_list.set_completions(items, flags))\n\n\nclass CompletionHandler(LSPViewEventListener):\n    def __init__(self, view: sublime.View) -> None:\n        super().__init__(view)\n        self.initialized = False\n        self.enabled = False\n\n    @classmethod\n    def is_applicable(cls, view_settings: dict) -> bool:\n        if 'completion' in settings.disabled_capabilities:\n            return False\n\n        syntax = view_settings.get('syntax')\n        return is_supported_syntax(syntax, client_configs.all) if syntax else False\n\n    def initialize(self) -> None:\n        self.initialized = True\n        session = session_for_view(self.view, 'completionProvider')\n        if session:\n            completionProvider = session.get_capability('completionProvider') or dict()  # type: dict\n            # A language server may have an empty dict as CompletionOptions. In that case,\n            # no trigger characters will be registered but we'll still respond to Sublime's\n            # usual query for completions. So the explicit check for None is necessary.\n            self.enabled = True\n\n            trigger_chars = completionProvider.get(\n                'triggerCharacters') or []\n            if trigger_chars:\n                self.register_trigger_chars(session, trigger_chars)\n            # This is to make ST match with labels that have a weird prefix like a space character.\n            self.view.settings().set(\"auto_complete_preserve_order\", \"none\")\n\n    def register_trigger_chars(self, session: Session, trigger_chars: List[str]) -> None:\n        completion_triggers = self.view.settings().get('auto_complete_triggers') or []  # type: List[Dict[str, str]]\n\n        completion_triggers.append({\n            'characters': \"\".join(trigger_chars),\n            'selector': \"- comment - punctuation.definition.string.end\"\n        })\n\n        self.view.settings().set('auto_complete_triggers', completion_triggers)\n\n    def on_query_completions(self, prefix: str, locations: List[int]) -> Optional[sublime.CompletionList]:\n        if not self.initialized:\n            self.initialize()\n        if not self.enabled:\n            return None\n        client = client_from_session(session_for_view(self.view, 'completionProvider', locations[0]))\n        if not client:\n            return None\n        self.manager.documents.purge_changes(self.view)\n        completion_list = sublime.CompletionList()\n        client.send_request(\n            Request.complete(text_document_position_params(self.view, locations[0])),\n            lambda res: self.handle_response(res, completion_list, self.view.change_id()),\n            lambda res: self.handle_error(res, completion_list))\n        return completion_list\n\n    def handle_response(self, response: Optional[Union[dict, List]],\n                        completion_list: sublime.CompletionList, change_id: Any) -> None:\n        response_items = []  # type: List[Dict]\n        incomplete = False\n        if isinstance(response, dict):\n            response_items = response[\"items\"] or []\n            incomplete = response.get(\"isIncomplete\", False)\n        elif isinstance(response, list):\n            response_items = response\n        response_items = sorted(response_items, key=lambda item: item.get(\"sortText\") or item[\"label\"])\n\n        flags = 0\n        if settings.only_show_lsp_completions:\n            flags |= sublime.INHIBIT_WORD_COMPLETIONS\n            flags |= sublime.INHIBIT_EXPLICIT_COMPLETIONS\n\n        if incomplete:\n            flags |= sublime.DYNAMIC_COMPLETIONS\n        resolve(completion_list, [format_completion(i, change_id) for i in response_items], flags)\n\n    def handle_error(self, error: dict, completion_list: sublime.CompletionList) -> None:\n        resolve(completion_list, [])\n        sublime.status_message('Completion error: ' + str(error.get('message')))\n", "path": "plugin/completion.py"}]}