diff --git a/fixtures/completion/html_no_completion.php b/fixtures/completion/html_no_completion.php
new file mode 100644
index 00000000..93184183
--- /dev/null
+++ b/fixtures/completion/html_no_completion.php
@@ -0,0 +1 @@
+<
diff --git a/src/CompletionProvider.php b/src/CompletionProvider.php
index 68c5a0cc..d774423e 100644
--- a/src/CompletionProvider.php
+++ b/src/CompletionProvider.php
@@ -10,7 +10,9 @@
Position,
CompletionList,
CompletionItem,
- CompletionItemKind
+ CompletionItemKind,
+ CompletionContext,
+ CompletionTriggerKind
};
use Microsoft\PhpParser;
use Microsoft\PhpParser\Node;
@@ -122,9 +124,10 @@ public function __construct(DefinitionResolver $definitionResolver, ReadableInde
*
* @param PhpDocument $doc The opened document
* @param Position $pos The cursor position
+ * @param CompletionContext $context The completion context
* @return CompletionList
*/
- public function provideCompletion(PhpDocument $doc, Position $pos): CompletionList
+ public function provideCompletion(PhpDocument $doc, Position $pos, CompletionContext $context = null): CompletionList
{
// This can be made much more performant if the tree follows specific invariants.
$node = $doc->getNodeAtPosition($pos);
@@ -152,7 +155,21 @@ public function provideCompletion(PhpDocument $doc, Position $pos): CompletionLi
// Inspect the type of expression under the cursor
- if ($node === null || $node instanceof Node\Statement\InlineHtml || $pos == new Position(0, 0)) {
+ $content = $doc->getContent();
+ $offset = $pos->toOffset($content);
+ if (
+ $node === null
+ || (
+ $node instanceof Node\Statement\InlineHtml
+ && (
+ $context === null
+ // Make sure to not suggest on the > trigger character in HTML
+ || $context->triggerKind === CompletionTriggerKind::INVOKED
+ || $context->triggerCharacter === '<'
+ )
+ )
+ || $pos == new Position(0, 0)
+ ) {
// HTML, beginning of file
// Inside HTML and at the beginning of the file, propose triggerKind = $triggerKind;
+ $this->triggerCharacter = $triggerCharacter;
+ }
+}
diff --git a/src/Protocol/CompletionTriggerKind.php b/src/Protocol/CompletionTriggerKind.php
new file mode 100644
index 00000000..d36129dc
--- /dev/null
+++ b/src/Protocol/CompletionTriggerKind.php
@@ -0,0 +1,16 @@
+
*/
- public function completion(TextDocumentIdentifier $textDocument, Position $position): Promise
+ public function completion(TextDocumentIdentifier $textDocument, Position $position, CompletionContext $context = null): Promise
{
- return coroutine(function () use ($textDocument, $position) {
+ return coroutine(function () use ($textDocument, $position, $context) {
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
- return $this->completionProvider->provideCompletion($document, $position);
+ return $this->completionProvider->provideCompletion($document, $position, $context);
});
}
diff --git a/tests/Server/TextDocument/CompletionTest.php b/tests/Server/TextDocument/CompletionTest.php
index 0d68ec3e..424dc3ca 100644
--- a/tests/Server/TextDocument/CompletionTest.php
+++ b/tests/Server/TextDocument/CompletionTest.php
@@ -17,7 +17,9 @@
Position,
CompletionList,
CompletionItem,
- CompletionItemKind
+ CompletionItemKind,
+ CompletionContext,
+ CompletionTriggerKind
};
use function LanguageServer\pathToUri;
@@ -464,6 +466,41 @@ public function testHtmlWithPrefix()
], true), $items);
}
+ public function testHtmlPrefixShouldNotTriggerCompletion()
+ {
+ $completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
+ $this->loader->open($completionUri, file_get_contents($completionUri));
+ $items = $this->textDocument->completion(
+ new TextDocumentIdentifier($completionUri),
+ new Position(0, 1),
+ new CompletionContext(CompletionTriggerKind::TRIGGER_CHARACTER, '>')
+ )->wait();
+ $this->assertEquals(new CompletionList([], true), $items);
+ }
+
+ public function testHtmlPrefixShouldTriggerCompletionIfManuallyInvoked()
+ {
+ $completionUri = pathToUri(__DIR__ . '/../../../fixtures/completion/html_no_completion.php');
+ $this->loader->open($completionUri, file_get_contents($completionUri));
+ $items = $this->textDocument->completion(
+ new TextDocumentIdentifier($completionUri),
+ new Position(0, 1),
+ new CompletionContext(CompletionTriggerKind::INVOKED)
+ )->wait();
+ $this->assertEquals(new CompletionList([
+ new CompletionItem(
+ '