diff --git a/packages/cxx-gen-lsp/src/gen_fwd_h.ts b/packages/cxx-gen-lsp/src/gen_fwd_h.ts index 06fab69b..c19ff3f9 100644 --- a/packages/cxx-gen-lsp/src/gen_fwd_h.ts +++ b/packages/cxx-gen-lsp/src/gen_fwd_h.ts @@ -50,7 +50,7 @@ public: [[nodiscard]] explicit operator bool() const { return repr_ && repr_->is_array(); } [[nodiscard]] auto size() const -> std::size_t { return repr_->size(); } [[nodiscard]] auto empty() const -> bool { return repr_->empty(); } - [[nodiscard]] auto at(int index) const -> const T& { return repr_->at(index); } + [[nodiscard]] auto at(int index) const -> T { return T(repr_->at(index)); } template void emplace_back(Args&&... args) { repr_->emplace_back(std::forward(args)...); } @@ -180,6 +180,24 @@ class Vector final : public LSPObject { void emplace_back(Args&&... args) { repr_->emplace_back(std::forward(args)...); } }; +template T> +class Vector final : public LSPObject { + public: + using LSPObject::LSPObject; + + [[nodiscard]] explicit operator bool() const { + return repr_ && repr_->is_array(); + } + [[nodiscard]] auto size() const -> std::size_t { return repr_->size(); } + [[nodiscard]] auto empty() const -> bool { return repr_->empty(); } + [[nodiscard]] auto at(int index) const -> T { return T(repr_->at(index)); } + + template + auto emplace_back(Args&&... args) -> T { + return T(repr_->emplace_back(std::forward(args)...)); + } +}; + template class Vector> final : public LSPObject { public: diff --git a/src/lsp/cxx/lsp/fwd.h b/src/lsp/cxx/lsp/fwd.h index 3569bfa6..6d8e207e 100644 --- a/src/lsp/cxx/lsp/fwd.h +++ b/src/lsp/cxx/lsp/fwd.h @@ -485,9 +485,7 @@ class Vector final : public LSPObject { } [[nodiscard]] auto size() const -> std::size_t { return repr_->size(); } [[nodiscard]] auto empty() const -> bool { return repr_->empty(); } - [[nodiscard]] auto at(int index) const -> const T& { - return repr_->at(index); - } + [[nodiscard]] auto at(int index) const -> T { return T(repr_->at(index)); } template void emplace_back(Args&&... args) { @@ -623,6 +621,24 @@ class Vector final : public LSPObject { } }; +template T> +class Vector final : public LSPObject { + public: + using LSPObject::LSPObject; + + [[nodiscard]] explicit operator bool() const { + return repr_ && repr_->is_array(); + } + [[nodiscard]] auto size() const -> std::size_t { return repr_->size(); } + [[nodiscard]] auto empty() const -> bool { return repr_->empty(); } + [[nodiscard]] auto at(int index) const -> T { return T(repr_->at(index)); } + + template + auto emplace_back(Args&&... args) -> T { + return T(repr_->emplace_back(std::forward(args)...)); + } +}; + template class Vector> final : public LSPObject { public: diff --git a/src/lsp/tests/test_types.cc b/src/lsp/tests/test_types.cc index 5a904d13..6c95a81b 100644 --- a/src/lsp/tests/test_types.cc +++ b/src/lsp/tests/test_types.cc @@ -1,6 +1,8 @@ #include #include +#include + #include "cxx/lsp/enums.h" #include "cxx/lsp/fwd.h" @@ -142,4 +144,108 @@ TEST(LSP, VariantArrayProperty) { ASSERT_EQ(std::get(*item.notebook()), "a_notebook"); ASSERT_EQ(notebookSelector.size(), 1); +} + +TEST(LSP, CompletionList) { + const char *kResponse = R"( +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "isIncomplete": false, + "items": [ + { + "filterText": "include", + "insertText": "include \"$0\"", + "insertTextFormat": 2, + "kind": 15, + "label": " include", + "sortText": "000000001", + "labelDetails": { + "detail": " \"header\"" + }, + "textEdit": { + "newText": "include \"$0\"", + "range": { + "end": { + "character": 4, + "line": 0 + }, + "start": { + "character": 1, + "line": 0 + } + } + } + } + ] + } +} +)"; + + auto response = json::parse(kResponse)["result"]; + + CompletionList completionList{response}; + + ASSERT_TRUE(completionList); + ASSERT_FALSE(completionList.isIncomplete()); + + ASSERT_EQ(completionList.items().size(), 1); + + auto items = completionList.items(); + auto item = items.at(0); + ASSERT_EQ(*item.filterText(), "include"); + ASSERT_EQ(*item.insertText(), "include \"$0\""); + ASSERT_EQ(item.insertTextFormat(), InsertTextFormat::kSnippet); + ASSERT_EQ(*item.kind(), CompletionItemKind::kSnippet); + ASSERT_EQ(item.label(), " include"); + ASSERT_EQ(*item.labelDetails()->detail(), " \"header\""); + ASSERT_EQ(item.sortText(), "000000001"); + + ASSERT_TRUE(std::holds_alternative(*item.textEdit())); + auto textEdit = std::get(*item.textEdit()); + + ASSERT_EQ(textEdit.newText(), "include \"$0\""); + auto range = textEdit.range(); + ASSERT_EQ(range.start().line(), 0); + ASSERT_EQ(range.start().character(), 1); + ASSERT_EQ(range.end().line(), 0); + ASSERT_EQ(range.end().character(), 4); +} + +TEST(LSP, CreateCompletionList) { + auto storage = json::object(); + + CompletionList completionList{storage}; + + completionList.isIncomplete(false); + + auto item = completionList.items().emplace_back(); + item.filterText("include"); + item.insertText("include \"$0\""); + item.insertTextFormat(InsertTextFormat::kSnippet); + item.kind(CompletionItemKind::kSnippet); + item.label(" include"); + + auto labelDetailsStorage = json::object(); + + item.labelDetails(CompletionItemLabelDetails(labelDetailsStorage)) + .detail(" \"header\""); + item.sortText("000000001"); + + auto textEditStorage = json::object(); + auto textEdit = TextEdit{textEditStorage}; + + textEdit.newText("include \"$0\""); + auto range = textEdit.range(); + range.start().line(0); + range.start().character(1); + range.end().line(0); + range.end().character(4); + + item.textEdit(std::move(textEdit)); + + ASSERT_TRUE(completionList); + + // std::cout << completionList.get().dump(2) << std::endl; } \ No newline at end of file