We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
space wrongly triggers autocompletion
following https://github.com/tomv564/LSP/pull/197#discussion_r151605795

<img width="418" alt="screen shot 2017-11-17 at 12 23 30 am" src="https://user-images.githubusercontent.com/1690993/32930648-f23bb3be-cb2d-11e7-96bf-437671397099.png">

It could be reproduced by typing `y` and `<space>` very quickly or when the language server responds slowly.

We might need to check if the context which triggered the completion is still a prefix of the current cursor.

--- 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 try:
5     from typing import Any, List, Dict, Tuple, Callable, Optional
6     assert Any and List and Dict and Tuple and Callable and Optional
7 except ImportError:
8     pass
9 
10 from .core.protocol import Request
11 from .core.settings import settings
12 from .core.logging import debug, exception_log
13 from .core.protocol import CompletionItemKind
14 from .core.clients import client_for_view
15 from .core.configurations import is_supported_syntax
16 from .core.documents import get_document_position, purge_did_change
17 
18 
19 NO_COMPLETION_SCOPES = 'comment, string'
20 completion_item_kind_names = {v: k for k, v in CompletionItemKind.__dict__.items()}
21 
22 
23 class CompletionState(object):
24     IDLE = 0
25     REQUESTING = 1
26     APPLYING = 2
27     CANCELLING = 3
28 
29 
30 resolvable_completion_items = []  # type: List[Any]
31 
32 
33 def find_completion_item(label: str) -> 'Optional[Any]':
34     matches = list(filter(lambda i: i.get("label") == label, resolvable_completion_items))
35     return matches[0] if matches else None
36 
37 
38 class CompletionContext(object):
39 
40     def __init__(self, begin):
41         self.begin = begin  # type: Optional[int]
42         self.end = None  # type: Optional[int]
43         self.region = None  # type: Optional[sublime.Region]
44         self.committing = False
45 
46     def committed_at(self, end):
47         self.end = end
48         self.region = sublime.Region(self.begin, self.end)
49         self.committing = False
50 
51 
52 current_completion = None  # type: Optional[CompletionContext]
53 
54 
55 def has_resolvable_completions(view):
56     client = client_for_view(view)
57     if client:
58         completionProvider = client.get_capability(
59             'completionProvider')
60         if completionProvider:
61             if completionProvider.get('resolveProvider', False):
62                 return True
63     return False
64 
65 
66 class CompletionSnippetHandler(sublime_plugin.EventListener):
67 
68     def on_query_completions(self, view, prefix, locations):
69         global current_completion
70         if settings.resolve_completion_for_snippets and has_resolvable_completions(view):
71             current_completion = CompletionContext(view.sel()[0].begin())
72 
73     def on_text_command(self, view, command_name, args):
74         if settings.resolve_completion_for_snippets and current_completion:
75             current_completion.committing = command_name in ('commit_completion', 'insert_best_completion')
76 
77     def on_modified(self, view):
78         global current_completion
79 
80         if settings.resolve_completion_for_snippets and view.file_name():
81             if current_completion and current_completion.committing:
82                 current_completion.committed_at(view.sel()[0].end())
83                 inserted = view.substr(current_completion.region)
84                 item = find_completion_item(inserted)
85                 if item:
86                     self.resolve_completion(item, view)
87                 else:
88                     current_completion = None
89 
90     def resolve_completion(self, item, view):
91         client = client_for_view(view)
92         if not client:
93             return
94 
95         client.send_request(
96             Request.resolveCompletionItem(item),
97             lambda response: self.handle_resolve_response(response, view))
98 
99     def handle_resolve_response(self, response, view):
100         # replace inserted text if a snippet was returned.
101         if current_completion and response.get('insertTextFormat') == 2:  # snippet
102             insertText = response.get('insertText')
103             try:
104                 sel = view.sel()
105                 sel.clear()
106                 sel.add(current_completion.region)
107                 view.run_command("insert_snippet", {"contents": insertText})
108             except Exception as err:
109                 exception_log("Error inserting snippet: " + insertText, err)
110 
111 
112 last_text_command = None
113 
114 
115 class CompletionHelper(sublime_plugin.EventListener):
116     def on_text_command(self, view, command_name, args):
117         global last_text_command
118         last_text_command = command_name
119 
120 
121 class CompletionHandler(sublime_plugin.ViewEventListener):
122     def __init__(self, view):
123         self.view = view
124         self.initialized = False
125         self.enabled = False
126         self.trigger_chars = []  # type: List[str]
127         self.resolve = False
128         self.resolve_details = []  # type: List[Tuple[str, str]]
129         self.state = CompletionState.IDLE
130         self.completions = []  # type: List[Any]
131         self.next_request = None  # type: Optional[Tuple[str, List[int]]]
132         self.last_prefix = ""
133         self.last_location = 0
134 
135     @classmethod
136     def is_applicable(cls, settings):
137         syntax = settings.get('syntax')
138         if syntax is not None:
139             return is_supported_syntax(syntax)
140         else:
141             return False
142 
143     def initialize(self):
144         self.initialized = True
145         client = client_for_view(self.view)
146         if client:
147             completionProvider = client.get_capability(
148                 'completionProvider')
149             if completionProvider:
150                 self.enabled = True
151                 self.trigger_chars = completionProvider.get(
152                     'triggerCharacters') or []
153                 self.has_resolve_provider = completionProvider.get('resolveProvider', False)
154 
155     def is_after_trigger_character(self, location):
156         if location > 0:
157             prev_char = self.view.substr(location - 1)
158             return prev_char in self.trigger_chars
159 
160     def is_same_completion(self, prefix, locations):
161         # completion requests from the same location with the same prefix are cached.
162         current_start = locations[0] - len(prefix)
163         last_start = self.last_location - len(self.last_prefix)
164         return prefix.startswith(self.last_prefix) and current_start == last_start
165 
166     def on_modified(self):
167         # hide completion when backspacing past last completion.
168         if self.view.sel()[0].begin() < self.last_location:
169             self.last_location = 0
170             self.view.run_command("hide_auto_complete")
171 
172     def on_query_completions(self, prefix, locations):
173         if self.view.match_selector(locations[0], NO_COMPLETION_SCOPES):
174             return (
175                 [],
176                 sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS
177             )
178 
179         if not self.initialized:
180             self.initialize()
181 
182         if self.enabled:
183             reuse_completion = self.is_same_completion(prefix, locations)
184             if self.state == CompletionState.IDLE:
185                 if not reuse_completion:
186                     self.last_prefix = prefix
187                     self.last_location = locations[0]
188                     self.do_request(prefix, locations)
189                     self.completions = []
190 
191             elif self.state in (CompletionState.REQUESTING, CompletionState.CANCELLING):
192                 self.next_request = (prefix, locations)
193                 self.state = CompletionState.CANCELLING
194 
195             elif self.state == CompletionState.APPLYING:
196                 self.state = CompletionState.IDLE
197 
198             return (
199                 self.completions,
200                 0 if not settings.only_show_lsp_completions
201                 else sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS
202             )
203 
204     def do_request(self, prefix: str, locations: 'List[int]'):
205         self.next_request = None
206         view = self.view
207 
208         # don't store client so we can handle restarts
209         client = client_for_view(view)
210         if not client:
211             return
212 
213         if settings.complete_all_chars or self.is_after_trigger_character(locations[0]):
214             purge_did_change(view.buffer_id())
215             document_position = get_document_position(view, locations[0])
216             if document_position:
217                 client.send_request(
218                     Request.complete(document_position),
219                     self.handle_response,
220                     self.handle_error)
221                 self.state = CompletionState.REQUESTING
222 
223     def format_completion(self, item: dict) -> 'Tuple[str, str]':
224         # Sublime handles snippets automatically, so we don't have to care about insertTextFormat.
225         label = item["label"]
226         # choose hint based on availability and user preference
227         hint = None
228         if settings.completion_hint_type == "auto":
229             hint = item.get("detail")
230             if not hint:
231                 kind = item.get("kind")
232                 if kind:
233                     hint = completion_item_kind_names[kind]
234         elif settings.completion_hint_type == "detail":
235             hint = item.get("detail")
236         elif settings.completion_hint_type == "kind":
237             kind = item.get("kind")
238             if kind:
239                 hint = completion_item_kind_names[kind]
240         # label is an alternative for insertText if insertText not provided
241         insert_text = item.get("insertText") or label
242         if len(insert_text) > 0 and insert_text[0] == '$':  # sublime needs leading '$' escaped.
243             insert_text = '\$' + insert_text[1:]
244         # only return label with a hint if available
245         return "\t  ".join((label, hint)) if hint else label, insert_text
246 
247     def handle_response(self, response: dict):
248         global resolvable_completion_items
249 
250         if self.state == CompletionState.REQUESTING:
251             items = response["items"] if isinstance(response,
252                                                     dict) else response
253             if len(items) > 1 and items[0].get("sortText") is not None:
254                 # If the first item has a sortText value, assume all of them have a sortText value.
255                 items = sorted(items, key=lambda item: item["sortText"])
256             self.completions = list(self.format_completion(item) for item in items)
257 
258             if self.has_resolve_provider:
259                 resolvable_completion_items = items
260 
261             # if insert_best_completion was just ran, undo it before presenting new completions.
262             prev_char = self.view.substr(self.view.sel()[0].begin() - 1)
263             if prev_char.isspace():
264                 if last_text_command == "insert_best_completion":
265                     self.view.run_command("undo")
266 
267             self.state = CompletionState.APPLYING
268             self.view.run_command("hide_auto_complete")
269             self.run_auto_complete()
270         elif self.state == CompletionState.CANCELLING:
271             if self.next_request:
272                 prefix, locations = self.next_request
273                 self.do_request(prefix, locations)
274         else:
275             debug('Got unexpected response while in state {}'.format(self.state))
276 
277     def handle_error(self, error: dict):
278         sublime.status_message('Completion error: ' + str(error.get('message')))
279         self.state = CompletionState.IDLE
280 
281     def run_auto_complete(self):
282         self.view.run_command(
283             "auto_complete", {
284                 'disable_auto_insert': True,
285                 'api_completions_only': settings.only_show_lsp_completions,
286                 'next_completion_if_showing': False
287             })
288
```
--- 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
@@ -168,6 +168,10 @@
         if self.view.sel()[0].begin() < self.last_location:
             self.last_location = 0
             self.view.run_command("hide_auto_complete")
+        # cancel current completion if the previous input is an space
+        prev_char = self.view.substr(self.view.sel()[0].begin() - 1)
+        if self.state == CompletionState.REQUESTING and prev_char.isspace():
+            self.state = CompletionState.CANCELLING
 
     def on_query_completions(self, prefix, locations):
         if self.view.match_selector(locations[0], NO_COMPLETION_SCOPES):

{"golden_diff": "diff --git a/plugin/completion.py b/plugin/completion.py\n--- a/plugin/completion.py\n+++ b/plugin/completion.py\n@@ -168,6 +168,10 @@\n         if self.view.sel()[0].begin() < self.last_location:\n             self.last_location = 0\n             self.view.run_command(\"hide_auto_complete\")\n+        # cancel current completion if the previous input is an space\n+        prev_char = self.view.substr(self.view.sel()[0].begin() - 1)\n+        if self.state == CompletionState.REQUESTING and prev_char.isspace():\n+            self.state = CompletionState.CANCELLING\n \n     def on_query_completions(self, prefix, locations):\n         if self.view.match_selector(locations[0], NO_COMPLETION_SCOPES):\n", "issue": "space wrongly triggers autocompletion\nfollowing https://github.com/tomv564/LSP/pull/197#discussion_r151605795\r\n\r\n<img width=\"418\" alt=\"screen shot 2017-11-17 at 12 23 30 am\" src=\"https://user-images.githubusercontent.com/1690993/32930648-f23bb3be-cb2d-11e7-96bf-437671397099.png\">\r\n\r\nIt could be reproduced by typing `y` and `<space>` very quickly or when the language server responds slowly.\r\n\r\nWe might need to check if the context which triggered the completion is still a prefix of the current cursor.\n", "before_files": [{"content": "import sublime\nimport sublime_plugin\n\ntry:\n    from typing import Any, List, Dict, Tuple, Callable, Optional\n    assert Any and List and Dict and Tuple and Callable and Optional\nexcept ImportError:\n    pass\n\nfrom .core.protocol import Request\nfrom .core.settings import settings\nfrom .core.logging import debug, exception_log\nfrom .core.protocol import CompletionItemKind\nfrom .core.clients import client_for_view\nfrom .core.configurations import is_supported_syntax\nfrom .core.documents import get_document_position, purge_did_change\n\n\nNO_COMPLETION_SCOPES = 'comment, string'\ncompletion_item_kind_names = {v: k for k, v in CompletionItemKind.__dict__.items()}\n\n\nclass CompletionState(object):\n    IDLE = 0\n    REQUESTING = 1\n    APPLYING = 2\n    CANCELLING = 3\n\n\nresolvable_completion_items = []  # type: List[Any]\n\n\ndef find_completion_item(label: str) -> 'Optional[Any]':\n    matches = list(filter(lambda i: i.get(\"label\") == label, resolvable_completion_items))\n    return matches[0] if matches else None\n\n\nclass CompletionContext(object):\n\n    def __init__(self, begin):\n        self.begin = begin  # type: Optional[int]\n        self.end = None  # type: Optional[int]\n        self.region = None  # type: Optional[sublime.Region]\n        self.committing = False\n\n    def committed_at(self, end):\n        self.end = end\n        self.region = sublime.Region(self.begin, self.end)\n        self.committing = False\n\n\ncurrent_completion = None  # type: Optional[CompletionContext]\n\n\ndef has_resolvable_completions(view):\n    client = client_for_view(view)\n    if client:\n        completionProvider = client.get_capability(\n            'completionProvider')\n        if completionProvider:\n            if completionProvider.get('resolveProvider', False):\n                return True\n    return False\n\n\nclass CompletionSnippetHandler(sublime_plugin.EventListener):\n\n    def on_query_completions(self, view, prefix, locations):\n        global current_completion\n        if settings.resolve_completion_for_snippets and has_resolvable_completions(view):\n            current_completion = CompletionContext(view.sel()[0].begin())\n\n    def on_text_command(self, view, command_name, args):\n        if settings.resolve_completion_for_snippets and current_completion:\n            current_completion.committing = command_name in ('commit_completion', 'insert_best_completion')\n\n    def on_modified(self, view):\n        global current_completion\n\n        if settings.resolve_completion_for_snippets and view.file_name():\n            if current_completion and current_completion.committing:\n                current_completion.committed_at(view.sel()[0].end())\n                inserted = view.substr(current_completion.region)\n                item = find_completion_item(inserted)\n                if item:\n                    self.resolve_completion(item, view)\n                else:\n                    current_completion = None\n\n    def resolve_completion(self, item, view):\n        client = client_for_view(view)\n        if not client:\n            return\n\n        client.send_request(\n            Request.resolveCompletionItem(item),\n            lambda response: self.handle_resolve_response(response, view))\n\n    def handle_resolve_response(self, response, view):\n        # replace inserted text if a snippet was returned.\n        if current_completion and response.get('insertTextFormat') == 2:  # snippet\n            insertText = response.get('insertText')\n            try:\n                sel = view.sel()\n                sel.clear()\n                sel.add(current_completion.region)\n                view.run_command(\"insert_snippet\", {\"contents\": insertText})\n            except Exception as err:\n                exception_log(\"Error inserting snippet: \" + insertText, err)\n\n\nlast_text_command = None\n\n\nclass CompletionHelper(sublime_plugin.EventListener):\n    def on_text_command(self, view, command_name, args):\n        global last_text_command\n        last_text_command = command_name\n\n\nclass CompletionHandler(sublime_plugin.ViewEventListener):\n    def __init__(self, view):\n        self.view = view\n        self.initialized = False\n        self.enabled = False\n        self.trigger_chars = []  # type: List[str]\n        self.resolve = False\n        self.resolve_details = []  # type: List[Tuple[str, str]]\n        self.state = CompletionState.IDLE\n        self.completions = []  # type: List[Any]\n        self.next_request = None  # type: Optional[Tuple[str, List[int]]]\n        self.last_prefix = \"\"\n        self.last_location = 0\n\n    @classmethod\n    def is_applicable(cls, settings):\n        syntax = settings.get('syntax')\n        if syntax is not None:\n            return is_supported_syntax(syntax)\n        else:\n            return False\n\n    def initialize(self):\n        self.initialized = True\n        client = client_for_view(self.view)\n        if client:\n            completionProvider = client.get_capability(\n                'completionProvider')\n            if completionProvider:\n                self.enabled = True\n                self.trigger_chars = completionProvider.get(\n                    'triggerCharacters') or []\n                self.has_resolve_provider = completionProvider.get('resolveProvider', False)\n\n    def is_after_trigger_character(self, location):\n        if location > 0:\n            prev_char = self.view.substr(location - 1)\n            return prev_char in self.trigger_chars\n\n    def is_same_completion(self, prefix, locations):\n        # completion requests from the same location with the same prefix are cached.\n        current_start = locations[0] - len(prefix)\n        last_start = self.last_location - len(self.last_prefix)\n        return prefix.startswith(self.last_prefix) and current_start == last_start\n\n    def on_modified(self):\n        # hide completion when backspacing past last completion.\n        if self.view.sel()[0].begin() < self.last_location:\n            self.last_location = 0\n            self.view.run_command(\"hide_auto_complete\")\n\n    def on_query_completions(self, prefix, locations):\n        if self.view.match_selector(locations[0], NO_COMPLETION_SCOPES):\n            return (\n                [],\n                sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS\n            )\n\n        if not self.initialized:\n            self.initialize()\n\n        if self.enabled:\n            reuse_completion = self.is_same_completion(prefix, locations)\n            if self.state == CompletionState.IDLE:\n                if not reuse_completion:\n                    self.last_prefix = prefix\n                    self.last_location = locations[0]\n                    self.do_request(prefix, locations)\n                    self.completions = []\n\n            elif self.state in (CompletionState.REQUESTING, CompletionState.CANCELLING):\n                self.next_request = (prefix, locations)\n                self.state = CompletionState.CANCELLING\n\n            elif self.state == CompletionState.APPLYING:\n                self.state = CompletionState.IDLE\n\n            return (\n                self.completions,\n                0 if not settings.only_show_lsp_completions\n                else sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS\n            )\n\n    def do_request(self, prefix: str, locations: 'List[int]'):\n        self.next_request = None\n        view = self.view\n\n        # don't store client so we can handle restarts\n        client = client_for_view(view)\n        if not client:\n            return\n\n        if settings.complete_all_chars or self.is_after_trigger_character(locations[0]):\n            purge_did_change(view.buffer_id())\n            document_position = get_document_position(view, locations[0])\n            if document_position:\n                client.send_request(\n                    Request.complete(document_position),\n                    self.handle_response,\n                    self.handle_error)\n                self.state = CompletionState.REQUESTING\n\n    def format_completion(self, item: dict) -> 'Tuple[str, str]':\n        # Sublime handles snippets automatically, so we don't have to care about insertTextFormat.\n        label = item[\"label\"]\n        # choose hint based on availability and user preference\n        hint = None\n        if settings.completion_hint_type == \"auto\":\n            hint = item.get(\"detail\")\n            if not hint:\n                kind = item.get(\"kind\")\n                if kind:\n                    hint = completion_item_kind_names[kind]\n        elif settings.completion_hint_type == \"detail\":\n            hint = item.get(\"detail\")\n        elif settings.completion_hint_type == \"kind\":\n            kind = item.get(\"kind\")\n            if kind:\n                hint = completion_item_kind_names[kind]\n        # label is an alternative for insertText if insertText not provided\n        insert_text = item.get(\"insertText\") or label\n        if len(insert_text) > 0 and insert_text[0] == '$':  # sublime needs leading '$' escaped.\n            insert_text = '\\$' + insert_text[1:]\n        # only return label with a hint if available\n        return \"\\t  \".join((label, hint)) if hint else label, insert_text\n\n    def handle_response(self, response: dict):\n        global resolvable_completion_items\n\n        if self.state == CompletionState.REQUESTING:\n            items = response[\"items\"] if isinstance(response,\n                                                    dict) else response\n            if len(items) > 1 and items[0].get(\"sortText\") is not None:\n                # If the first item has a sortText value, assume all of them have a sortText value.\n                items = sorted(items, key=lambda item: item[\"sortText\"])\n            self.completions = list(self.format_completion(item) for item in items)\n\n            if self.has_resolve_provider:\n                resolvable_completion_items = items\n\n            # if insert_best_completion was just ran, undo it before presenting new completions.\n            prev_char = self.view.substr(self.view.sel()[0].begin() - 1)\n            if prev_char.isspace():\n                if last_text_command == \"insert_best_completion\":\n                    self.view.run_command(\"undo\")\n\n            self.state = CompletionState.APPLYING\n            self.view.run_command(\"hide_auto_complete\")\n            self.run_auto_complete()\n        elif self.state == CompletionState.CANCELLING:\n            if self.next_request:\n                prefix, locations = self.next_request\n                self.do_request(prefix, locations)\n        else:\n            debug('Got unexpected response while in state {}'.format(self.state))\n\n    def handle_error(self, error: dict):\n        sublime.status_message('Completion error: ' + str(error.get('message')))\n        self.state = CompletionState.IDLE\n\n    def run_auto_complete(self):\n        self.view.run_command(\n            \"auto_complete\", {\n                'disable_auto_insert': True,\n                'api_completions_only': settings.only_show_lsp_completions,\n                'next_completion_if_showing': False\n            })\n", "path": "plugin/completion.py"}], "after_files": [{"content": "import sublime\nimport sublime_plugin\n\ntry:\n    from typing import Any, List, Dict, Tuple, Callable, Optional\n    assert Any and List and Dict and Tuple and Callable and Optional\nexcept ImportError:\n    pass\n\nfrom .core.protocol import Request\nfrom .core.settings import settings\nfrom .core.logging import debug, exception_log\nfrom .core.protocol import CompletionItemKind\nfrom .core.clients import client_for_view\nfrom .core.configurations import is_supported_syntax\nfrom .core.documents import get_document_position, purge_did_change\n\n\nNO_COMPLETION_SCOPES = 'comment, string'\ncompletion_item_kind_names = {v: k for k, v in CompletionItemKind.__dict__.items()}\n\n\nclass CompletionState(object):\n    IDLE = 0\n    REQUESTING = 1\n    APPLYING = 2\n    CANCELLING = 3\n\n\nresolvable_completion_items = []  # type: List[Any]\n\n\ndef find_completion_item(label: str) -> 'Optional[Any]':\n    matches = list(filter(lambda i: i.get(\"label\") == label, resolvable_completion_items))\n    return matches[0] if matches else None\n\n\nclass CompletionContext(object):\n\n    def __init__(self, begin):\n        self.begin = begin  # type: Optional[int]\n        self.end = None  # type: Optional[int]\n        self.region = None  # type: Optional[sublime.Region]\n        self.committing = False\n\n    def committed_at(self, end):\n        self.end = end\n        self.region = sublime.Region(self.begin, self.end)\n        self.committing = False\n\n\ncurrent_completion = None  # type: Optional[CompletionContext]\n\n\ndef has_resolvable_completions(view):\n    client = client_for_view(view)\n    if client:\n        completionProvider = client.get_capability(\n            'completionProvider')\n        if completionProvider:\n            if completionProvider.get('resolveProvider', False):\n                return True\n    return False\n\n\nclass CompletionSnippetHandler(sublime_plugin.EventListener):\n\n    def on_query_completions(self, view, prefix, locations):\n        global current_completion\n        if settings.resolve_completion_for_snippets and has_resolvable_completions(view):\n            current_completion = CompletionContext(view.sel()[0].begin())\n\n    def on_text_command(self, view, command_name, args):\n        if settings.resolve_completion_for_snippets and current_completion:\n            current_completion.committing = command_name in ('commit_completion', 'insert_best_completion')\n\n    def on_modified(self, view):\n        global current_completion\n\n        if settings.resolve_completion_for_snippets and view.file_name():\n            if current_completion and current_completion.committing:\n                current_completion.committed_at(view.sel()[0].end())\n                inserted = view.substr(current_completion.region)\n                item = find_completion_item(inserted)\n                if item:\n                    self.resolve_completion(item, view)\n                else:\n                    current_completion = None\n\n    def resolve_completion(self, item, view):\n        client = client_for_view(view)\n        if not client:\n            return\n\n        client.send_request(\n            Request.resolveCompletionItem(item),\n            lambda response: self.handle_resolve_response(response, view))\n\n    def handle_resolve_response(self, response, view):\n        # replace inserted text if a snippet was returned.\n        if current_completion and response.get('insertTextFormat') == 2:  # snippet\n            insertText = response.get('insertText')\n            try:\n                sel = view.sel()\n                sel.clear()\n                sel.add(current_completion.region)\n                view.run_command(\"insert_snippet\", {\"contents\": insertText})\n            except Exception as err:\n                exception_log(\"Error inserting snippet: \" + insertText, err)\n\n\nlast_text_command = None\n\n\nclass CompletionHelper(sublime_plugin.EventListener):\n    def on_text_command(self, view, command_name, args):\n        global last_text_command\n        last_text_command = command_name\n\n\nclass CompletionHandler(sublime_plugin.ViewEventListener):\n    def __init__(self, view):\n        self.view = view\n        self.initialized = False\n        self.enabled = False\n        self.trigger_chars = []  # type: List[str]\n        self.resolve = False\n        self.resolve_details = []  # type: List[Tuple[str, str]]\n        self.state = CompletionState.IDLE\n        self.completions = []  # type: List[Any]\n        self.next_request = None  # type: Optional[Tuple[str, List[int]]]\n        self.last_prefix = \"\"\n        self.last_location = 0\n\n    @classmethod\n    def is_applicable(cls, settings):\n        syntax = settings.get('syntax')\n        if syntax is not None:\n            return is_supported_syntax(syntax)\n        else:\n            return False\n\n    def initialize(self):\n        self.initialized = True\n        client = client_for_view(self.view)\n        if client:\n            completionProvider = client.get_capability(\n                'completionProvider')\n            if completionProvider:\n                self.enabled = True\n                self.trigger_chars = completionProvider.get(\n                    'triggerCharacters') or []\n                self.has_resolve_provider = completionProvider.get('resolveProvider', False)\n\n    def is_after_trigger_character(self, location):\n        if location > 0:\n            prev_char = self.view.substr(location - 1)\n            return prev_char in self.trigger_chars\n\n    def is_same_completion(self, prefix, locations):\n        # completion requests from the same location with the same prefix are cached.\n        current_start = locations[0] - len(prefix)\n        last_start = self.last_location - len(self.last_prefix)\n        return prefix.startswith(self.last_prefix) and current_start == last_start\n\n    def on_modified(self):\n        # hide completion when backspacing past last completion.\n        if self.view.sel()[0].begin() < self.last_location:\n            self.last_location = 0\n            self.view.run_command(\"hide_auto_complete\")\n        # cancel current completion if the previous input is an space\n        prev_char = self.view.substr(self.view.sel()[0].begin() - 1)\n        if self.state == CompletionState.REQUESTING and prev_char.isspace():\n            self.state = CompletionState.CANCELLING\n\n    def on_query_completions(self, prefix, locations):\n        if self.view.match_selector(locations[0], NO_COMPLETION_SCOPES):\n            return (\n                [],\n                sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS\n            )\n\n        if not self.initialized:\n            self.initialize()\n\n        if self.enabled:\n            reuse_completion = self.is_same_completion(prefix, locations)\n            if self.state == CompletionState.IDLE:\n                if not reuse_completion:\n                    self.last_prefix = prefix\n                    self.last_location = locations[0]\n                    self.do_request(prefix, locations)\n                    self.completions = []\n\n            elif self.state in (CompletionState.REQUESTING, CompletionState.CANCELLING):\n                self.next_request = (prefix, locations)\n                self.state = CompletionState.CANCELLING\n\n            elif self.state == CompletionState.APPLYING:\n                self.state = CompletionState.IDLE\n\n            return (\n                self.completions,\n                0 if not settings.only_show_lsp_completions\n                else sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS\n            )\n\n    def do_request(self, prefix: str, locations: 'List[int]'):\n        self.next_request = None\n        view = self.view\n\n        # don't store client so we can handle restarts\n        client = client_for_view(view)\n        if not client:\n            return\n\n        if settings.complete_all_chars or self.is_after_trigger_character(locations[0]):\n            purge_did_change(view.buffer_id())\n            document_position = get_document_position(view, locations[0])\n            if document_position:\n                client.send_request(\n                    Request.complete(document_position),\n                    self.handle_response,\n                    self.handle_error)\n                self.state = CompletionState.REQUESTING\n\n    def format_completion(self, item: dict) -> 'Tuple[str, str]':\n        # Sublime handles snippets automatically, so we don't have to care about insertTextFormat.\n        label = item[\"label\"]\n        # choose hint based on availability and user preference\n        hint = None\n        if settings.completion_hint_type == \"auto\":\n            hint = item.get(\"detail\")\n            if not hint:\n                kind = item.get(\"kind\")\n                if kind:\n                    hint = completion_item_kind_names[kind]\n        elif settings.completion_hint_type == \"detail\":\n            hint = item.get(\"detail\")\n        elif settings.completion_hint_type == \"kind\":\n            kind = item.get(\"kind\")\n            if kind:\n                hint = completion_item_kind_names[kind]\n        # label is an alternative for insertText if insertText not provided\n        insert_text = item.get(\"insertText\") or label\n        if len(insert_text) > 0 and insert_text[0] == '$':  # sublime needs leading '$' escaped.\n            insert_text = '\\$' + insert_text[1:]\n        # only return label with a hint if available\n        return \"\\t  \".join((label, hint)) if hint else label, insert_text\n\n    def handle_response(self, response: dict):\n        global resolvable_completion_items\n\n        if self.state == CompletionState.REQUESTING:\n            items = response[\"items\"] if isinstance(response,\n                                                    dict) else response\n            if len(items) > 1 and items[0].get(\"sortText\") is not None:\n                # If the first item has a sortText value, assume all of them have a sortText value.\n                items = sorted(items, key=lambda item: item[\"sortText\"])\n            self.completions = list(self.format_completion(item) for item in items)\n\n            if self.has_resolve_provider:\n                resolvable_completion_items = items\n\n            # if insert_best_completion was just ran, undo it before presenting new completions.\n            prev_char = self.view.substr(self.view.sel()[0].begin() - 1)\n            if prev_char.isspace():\n                if last_text_command == \"insert_best_completion\":\n                    self.view.run_command(\"undo\")\n\n            self.state = CompletionState.APPLYING\n            self.view.run_command(\"hide_auto_complete\")\n            self.run_auto_complete()\n        elif self.state == CompletionState.CANCELLING:\n            if self.next_request:\n                prefix, locations = self.next_request\n                self.do_request(prefix, locations)\n        else:\n            debug('Got unexpected response while in state {}'.format(self.state))\n\n    def handle_error(self, error: dict):\n        sublime.status_message('Completion error: ' + str(error.get('message')))\n        self.state = CompletionState.IDLE\n\n    def run_auto_complete(self):\n        self.view.run_command(\n            \"auto_complete\", {\n                'disable_auto_insert': True,\n                'api_completions_only': settings.only_show_lsp_completions,\n                'next_completion_if_showing': False\n            })\n", "path": "plugin/completion.py"}]}