From ef516ad3f704ff6887b194d3d8ec82273856e580 Mon Sep 17 00:00:00 2001
From: i582 <51853996+i582@users.noreply.github.com>
Date: Sat, 8 Feb 2025 02:32:08 +0400
Subject: [PATCH] feat(completion): add `bounced<>` to completion

Fixes #84
---
 server/src/completion/CompletionContext.ts    |  8 +++++++
 .../BouncedTypeCompletionProvider.ts          | 20 ++++++++++++++++
 .../suite/testcases/completion/messages.test  | 24 +++++++++++++++++++
 server/src/server.ts                          |  2 ++
 4 files changed, 54 insertions(+)
 create mode 100644 server/src/completion/providers/BouncedTypeCompletionProvider.ts

diff --git a/server/src/completion/CompletionContext.ts b/server/src/completion/CompletionContext.ts
index 18a74391..ed7452ba 100644
--- a/server/src/completion/CompletionContext.ts
+++ b/server/src/completion/CompletionContext.ts
@@ -26,6 +26,7 @@ export class CompletionContext {
     inTraitList: boolean = false
     inParameter: boolean = false
     isMessageContext: boolean = false
+    isBouncedMessage: boolean = false
     isInitOfName: boolean = false
 
     contextTy: Ty | null = null
@@ -120,6 +121,13 @@ export class CompletionContext {
             this.isMessageContext = true
         }
 
+        if (parent.type === "parameter") {
+            const grand = parent.parent
+            if (grand?.type === "bounced_function") {
+                this.isBouncedMessage = true
+            }
+        }
+
         if (parent.type === "parameter") {
             const grand = parent.parent
             if (grand?.type === "receive_function") {
diff --git a/server/src/completion/providers/BouncedTypeCompletionProvider.ts b/server/src/completion/providers/BouncedTypeCompletionProvider.ts
new file mode 100644
index 00000000..b4cbff2b
--- /dev/null
+++ b/server/src/completion/providers/BouncedTypeCompletionProvider.ts
@@ -0,0 +1,20 @@
+import {CompletionProvider} from "@server/completion/CompletionProvider"
+import {CompletionItemKind, InsertTextFormat} from "vscode-languageserver-types"
+import {CompletionContext} from "@server/completion/CompletionContext"
+import {CompletionResult, CompletionWeight} from "@server/completion/WeightedCompletionItem"
+
+export class BouncedTypeCompletionProvider implements CompletionProvider {
+    isAvailable(ctx: CompletionContext): boolean {
+        return ctx.isType && ctx.isBouncedMessage
+    }
+
+    addCompletion(_ctx: CompletionContext, result: CompletionResult): void {
+        result.add({
+            label: "bounced<Type>",
+            kind: CompletionItemKind.Keyword,
+            insertText: "bounced<$1>$0",
+            insertTextFormat: InsertTextFormat.Snippet,
+            weight: CompletionWeight.KEYWORD,
+        })
+    }
+}
diff --git a/server/src/e2e/suite/testcases/completion/messages.test b/server/src/e2e/suite/testcases/completion/messages.test
index 562a379a..f0c24bb2 100644
--- a/server/src/e2e/suite/testcases/completion/messages.test
+++ b/server/src/e2e/suite/testcases/completion/messages.test
@@ -31,3 +31,27 @@ contract Foo {
 }
 ------------------------------------------------------------------------
 21 Bar
+
+========================================================================
+Completion in bounced function 2
+========================================================================
+primitive Int;
+primitive Address;
+primitive String;
+
+struct Foo {}
+message Bar {}
+trait Var {}
+
+contract Foo {
+    bounced(msg: <caret>) {}
+}
+------------------------------------------------------------------------
+13 bounced<Type>
+13 map<K, V>
+9  Address
+9  Int
+9  String
+21 Bar
+21 Foo
+24 Var
diff --git a/server/src/server.ts b/server/src/server.ts
index 1099782e..3cc8c041 100644
--- a/server/src/server.ts
+++ b/server/src/server.ts
@@ -78,6 +78,7 @@ import {MissedFieldInContractInspection} from "@server/inspections/MissedFieldIn
 import {Node as SyntaxNode} from "web-tree-sitter"
 import {TraitOrContractConstantsCompletionProvider} from "@server/completion/providers/TraitOrContractConstantsCompletionProvider"
 import {generateTlBTypeDoc} from "@server/documentation/tlb_type_documentation"
+import {BouncedTypeCompletionProvider} from "@server/completion/providers/BouncedTypeCompletionProvider"
 
 /**
  * Whenever LS is initialized.
@@ -622,6 +623,7 @@ connection.onInitialize(async (params: lsp.InitializeParams): Promise<lsp.Initia
                 new SnippetsCompletionProvider(),
                 new KeywordsCompletionProvider(),
                 new MapTypeCompletionProvider(),
+                new BouncedTypeCompletionProvider(),
                 new ContractDeclCompletionProvider(),
                 new TopLevelFunctionCompletionProvider(),
                 new MemberFunctionCompletionProvider(),