支持全局函数补全
This commit is contained in:
parent
aac12137cb
commit
dc713e6893
|
|
@ -68,24 +68,35 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
|||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/utils/args_parser.cpp
|
||||
src/language/tsl_keywords.cpp
|
||||
src/utils/string.cpp
|
||||
src/language/keyword_manager.cpp
|
||||
src/core/dispacther.cpp
|
||||
src/core/server.cpp
|
||||
src/scheduler/request.cpp
|
||||
src/provider/base/provider_registry.cpp
|
||||
src/provider/base/provider_interface.cpp
|
||||
src/provider/base/bootstrap.cpp
|
||||
src/provider/base/interface.cpp
|
||||
src/provider/initialize/initialize.cpp
|
||||
src/provider/initialized/initialized.cpp
|
||||
src/provider/text_document/did_open.cpp
|
||||
src/provider/text_document/did_change.cpp
|
||||
src/provider/text_document/did_close.cpp
|
||||
src/provider/text_document/completion.cpp
|
||||
src/provider/text_document/semantic_tokens.cpp
|
||||
# src/provider/text_document/semantic_tokens.cpp
|
||||
src/provider/shutdown/shutdown.cpp
|
||||
src/provider/exit/exit.cpp
|
||||
src/provider/cancel_request/cancel_request.cpp
|
||||
src/provider/trace/set_trace.cpp
|
||||
src/provider/completion_item/resolve.cpp
|
||||
src/service/base/bootstrap.cpp
|
||||
src/service/utils/text_coordinates.cpp
|
||||
src/service/detail/document/text_document.cpp
|
||||
src/service/detail/symbol/symbol_extractor.cpp
|
||||
src/service/detail/symbol/global_symbol_store.cpp
|
||||
src/service/detail/symbol/workspace_symbol_store.cpp
|
||||
src/service/detail/symbol/tsf_loader.cpp
|
||||
src/service/document.cpp
|
||||
src/service/symbol.cpp
|
||||
src/service/parser.cpp
|
||||
src/tree-sitter/parser.c)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace lsp::core
|
|||
RequestDispatcher::RequestDispatcher()
|
||||
{
|
||||
// 预创建 lifecycle callback,避免每次调用时都创建新的 lambda
|
||||
context_lifecycle_callback_ = [this](providers::ServerLifecycleEvent event) {
|
||||
context_lifecycle_callback_ = [this](provider::ServerLifecycleEvent event) {
|
||||
NotifyAllLifecycleListeners(event);
|
||||
};
|
||||
}
|
||||
|
|
@ -19,13 +19,13 @@ namespace lsp::core
|
|||
spdlog::debug("RequestScheduler set in dispatcher");
|
||||
}
|
||||
|
||||
void RequestDispatcher::SetSeviceContainer(service::Container* service_container)
|
||||
void RequestDispatcher::SetSeviceRegistry(service::Registry* service_registry)
|
||||
{
|
||||
service_container_ = service_container;
|
||||
spdlog::debug("ServiceContainer is set in dispatcher");
|
||||
service_registry_ = service_registry;
|
||||
spdlog::debug("ServiceRegistry is set in dispatcher");
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterRequestProvider(std::shared_ptr<providers::IRequestProvider> provider)
|
||||
void RequestDispatcher::RegisterRequestProvider(std::shared_ptr<provider::IRequestProvider> provider)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
std::string method = provider->GetMethod();
|
||||
|
|
@ -33,7 +33,7 @@ namespace lsp::core
|
|||
providers_[method] = provider;
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterNotificationProvider(std::shared_ptr<providers::INotificationProvider> provider)
|
||||
void RequestDispatcher::RegisterNotificationProvider(std::shared_ptr<provider::INotificationProvider> provider)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
std::string method = provider->GetMethod();
|
||||
|
|
@ -41,7 +41,7 @@ namespace lsp::core
|
|||
notification_providers_[method] = provider;
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterLifecycleCallback(providers::LifecycleCallback callback)
|
||||
void RequestDispatcher::RegisterLifecycleCallback(provider::LifecycleCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
lifecycle_callbacks_.push_back(std::move(callback));
|
||||
|
|
@ -50,7 +50,7 @@ namespace lsp::core
|
|||
|
||||
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
|
||||
{
|
||||
providers::ExecutionContext context(context_lifecycle_callback_, *request_scheduler_, *service_container_);
|
||||
provider::ExecutionContext context(context_lifecycle_callback_, *request_scheduler_, *service_registry_);
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
auto it = providers_.find(request.method);
|
||||
|
|
@ -66,7 +66,7 @@ namespace lsp::core
|
|||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Provider error for method [{}]: {}", request.method, e.what());
|
||||
return providers::BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, e.what());
|
||||
return provider::BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, e.what());
|
||||
}
|
||||
}
|
||||
return HandleUnknownRequest(request);
|
||||
|
|
@ -74,7 +74,7 @@ namespace lsp::core
|
|||
|
||||
void RequestDispatcher::Dispatch(const protocol::NotificationMessage& notification)
|
||||
{
|
||||
providers::ExecutionContext context(context_lifecycle_callback_, *request_scheduler_, *service_container_);
|
||||
provider::ExecutionContext context(context_lifecycle_callback_, *request_scheduler_, *service_registry_);
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
auto it = notification_providers_.find(notification.method);
|
||||
|
|
@ -134,26 +134,26 @@ namespace lsp::core
|
|||
return requests;
|
||||
}
|
||||
|
||||
void RequestDispatcher::NotifyAllLifecycleListeners(providers::ServerLifecycleEvent event)
|
||||
void RequestDispatcher::NotifyAllLifecycleListeners(provider::ServerLifecycleEvent event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
|
||||
std::string event_name;
|
||||
switch (event)
|
||||
{
|
||||
case providers::ServerLifecycleEvent::kInitializing:
|
||||
case provider::ServerLifecycleEvent::kInitializing:
|
||||
event_name = "Initializing";
|
||||
break;
|
||||
case providers::ServerLifecycleEvent::kInitialized:
|
||||
case provider::ServerLifecycleEvent::kInitialized:
|
||||
event_name = "Initialized";
|
||||
break;
|
||||
case providers::ServerLifecycleEvent::kInitializeFailed:
|
||||
case provider::ServerLifecycleEvent::kInitializeFailed:
|
||||
event_name = "InitializeFailed";
|
||||
break;
|
||||
case providers::ServerLifecycleEvent::kShuttingDown:
|
||||
case provider::ServerLifecycleEvent::kShuttingDown:
|
||||
event_name = "ShuttingDown";
|
||||
break;
|
||||
case providers::ServerLifecycleEvent::kShutdown:
|
||||
case provider::ServerLifecycleEvent::kShutdown:
|
||||
event_name = "Shutdown";
|
||||
break;
|
||||
}
|
||||
|
|
@ -175,7 +175,7 @@ namespace lsp::core
|
|||
|
||||
std::string RequestDispatcher::HandleUnknownRequest(const protocol::RequestMessage& request)
|
||||
{
|
||||
return providers::BuildErrorResponseMessage(request, protocol::ErrorCodes::kMethodNotFound, "Method not found: " + request.method);
|
||||
return provider::BuildErrorResponseMessage(request, protocol::ErrorCodes::kMethodNotFound, "Method not found: " + request.method);
|
||||
}
|
||||
|
||||
void RequestDispatcher::HandleUnknownNotification(const protocol::NotificationMessage& notification)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
#include <vector>
|
||||
#include <shared_mutex>
|
||||
#include "../protocol/protocol.hpp"
|
||||
#include "../provider/base/provider_interface.hpp"
|
||||
#include "../service/base/container.hpp"
|
||||
#include "../provider/base/interface.hpp"
|
||||
|
||||
namespace lsp::core
|
||||
{
|
||||
|
|
@ -16,12 +15,12 @@ namespace lsp::core
|
|||
~RequestDispatcher() = default;
|
||||
|
||||
void SetRequestScheduler(scheduler::Request* scheduler);
|
||||
void SetSeviceContainer(service::Container* service_container);
|
||||
void SetSeviceRegistry(service::Registry* service_registry);
|
||||
|
||||
void RegisterRequestProvider(std::shared_ptr<providers::IRequestProvider> provider);
|
||||
void RegisterNotificationProvider(std::shared_ptr<providers::INotificationProvider> provider);
|
||||
void RegisterRequestProvider(std::shared_ptr<provider::IRequestProvider> provider);
|
||||
void RegisterNotificationProvider(std::shared_ptr<provider::INotificationProvider> provider);
|
||||
|
||||
void RegisterLifecycleCallback(providers::LifecycleCallback callback);
|
||||
void RegisterLifecycleCallback(provider::LifecycleCallback callback);
|
||||
|
||||
std::string Dispatch(const protocol::RequestMessage& request);
|
||||
void Dispatch(const protocol::NotificationMessage& notification);
|
||||
|
|
@ -33,24 +32,24 @@ namespace lsp::core
|
|||
std::vector<std::string> GetAllSupportedMethods() const;
|
||||
|
||||
private:
|
||||
void NotifyAllLifecycleListeners(providers::ServerLifecycleEvent event);
|
||||
void NotifyAllLifecycleListeners(provider::ServerLifecycleEvent event);
|
||||
std::string HandleUnknownRequest(const protocol::RequestMessage& request);
|
||||
void HandleUnknownNotification(const protocol::NotificationMessage& notification);
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex providers_mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<providers::IRequestProvider>> providers_;
|
||||
std::unordered_map<std::string, std::shared_ptr<provider::IRequestProvider>> providers_;
|
||||
|
||||
mutable std::shared_mutex notification_providers_mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<providers::INotificationProvider>> notification_providers_;
|
||||
std::unordered_map<std::string, std::shared_ptr<provider::INotificationProvider>> notification_providers_;
|
||||
|
||||
std::mutex callbacks_mutex_;
|
||||
std::vector<providers::LifecycleCallback> lifecycle_callbacks_;
|
||||
std::vector<provider::LifecycleCallback> lifecycle_callbacks_;
|
||||
|
||||
providers::LifecycleCallback context_lifecycle_callback_;
|
||||
provider::LifecycleCallback context_lifecycle_callback_;
|
||||
|
||||
// 服务引用
|
||||
scheduler::Request* request_scheduler_ = nullptr;
|
||||
service::Container* service_container_ = nullptr;
|
||||
service::Registry* service_registry_ = nullptr;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include "../provider/base/provider_registry.hpp"
|
||||
#include "../provider/base/bootstrap.hpp"
|
||||
#include "../service/base/bootstrap.hpp"
|
||||
#include "../protocol/transform/facade.hpp"
|
||||
#include "../service/document.hpp"
|
||||
#include "./server.hpp"
|
||||
|
||||
namespace lsp::core
|
||||
|
|
@ -171,7 +171,7 @@ namespace lsp::core
|
|||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Request processing failed: {}", e.what());
|
||||
return providers::BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, e.what());
|
||||
return provider::BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, e.what());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -199,30 +199,30 @@ namespace lsp::core
|
|||
spdlog::debug("Received response - id: {}", id_str);
|
||||
}
|
||||
|
||||
void LspServer::OnLifecycleEvent(providers::ServerLifecycleEvent event)
|
||||
void LspServer::OnLifecycleEvent(provider::ServerLifecycleEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case providers::ServerLifecycleEvent::kInitializing:
|
||||
case provider::ServerLifecycleEvent::kInitializing:
|
||||
spdlog::info("Server initializing...");
|
||||
break;
|
||||
|
||||
case providers::ServerLifecycleEvent::kInitialized:
|
||||
case provider::ServerLifecycleEvent::kInitialized:
|
||||
is_initialized_ = true;
|
||||
spdlog::info("Server initialized successfully");
|
||||
break;
|
||||
|
||||
case providers::ServerLifecycleEvent::kInitializeFailed:
|
||||
case provider::ServerLifecycleEvent::kInitializeFailed:
|
||||
is_initialized_ = false;
|
||||
spdlog::error("Server initialization failed");
|
||||
break;
|
||||
|
||||
case providers::ServerLifecycleEvent::kShuttingDown:
|
||||
case provider::ServerLifecycleEvent::kShuttingDown:
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("Server entering shutdown state");
|
||||
break;
|
||||
|
||||
case providers::ServerLifecycleEvent::kShutdown:
|
||||
case provider::ServerLifecycleEvent::kShutdown:
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("Server shutdown complete");
|
||||
break;
|
||||
|
|
@ -232,8 +232,8 @@ namespace lsp::core
|
|||
bool LspServer::RequiresSyncProcessing(const std::string& method) const
|
||||
{
|
||||
static const std::unordered_set<std::string> sync_methods = {
|
||||
"initialize", // 必须同步完成
|
||||
"shutdown" // 必须同步完成
|
||||
"initialize",
|
||||
"shutdown"
|
||||
};
|
||||
|
||||
return sync_methods.count(method) > 0;
|
||||
|
|
@ -241,15 +241,12 @@ namespace lsp::core
|
|||
|
||||
bool LspServer::CanProcessRequest(const std::string& method) const
|
||||
{
|
||||
// 未初始化状态
|
||||
if (!is_initialized_)
|
||||
return method == "initialize" || method == "exit";
|
||||
|
||||
// 关闭中状态
|
||||
if (is_shutting_down_)
|
||||
return method == "exit";
|
||||
|
||||
// 正常状态 - 接受所有请求
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -281,10 +278,10 @@ namespace lsp::core
|
|||
dispatcher_.SetRequestScheduler(&request_scheduler_);
|
||||
|
||||
dispatcher_.RegisterLifecycleCallback(
|
||||
[this](providers::ServerLifecycleEvent event) {
|
||||
[this](provider::ServerLifecycleEvent event) {
|
||||
OnLifecycleEvent(event);
|
||||
});
|
||||
providers::RegisterAllProviders(dispatcher_);
|
||||
provider::RegisterAllProviders(dispatcher_);
|
||||
|
||||
request_scheduler_.SetResponseCallback([this](const std::string& response) {
|
||||
SendResponse(response);
|
||||
|
|
@ -297,8 +294,8 @@ namespace lsp::core
|
|||
{
|
||||
spdlog::debug("Initializing extension services...");
|
||||
|
||||
service_container_.RegisterService(std::make_shared<service::Document>());
|
||||
dispatcher_.SetSeviceContainer(&service_container_);
|
||||
service::RegisterAllServices(service_registry_);
|
||||
dispatcher_.SetSeviceRegistry(&service_registry_);
|
||||
|
||||
spdlog::debug("Extension services initialized");
|
||||
}
|
||||
|
|
@ -306,7 +303,7 @@ namespace lsp::core
|
|||
void LspServer::SendError(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message)
|
||||
{
|
||||
spdlog::warn("Sending error response - method: {}, code: {}, message: {}", request.method, static_cast<int>(code), message);
|
||||
std::string error_response = providers::BuildErrorResponseMessage(request, code, message);
|
||||
std::string error_response = provider::BuildErrorResponseMessage(request, code, message);
|
||||
SendResponse(error_response);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace lsp::core
|
|||
void HandleResponse(const protocol::ResponseMessage& response);
|
||||
|
||||
// 生命周期事件处理
|
||||
void OnLifecycleEvent(providers::ServerLifecycleEvent event);
|
||||
void OnLifecycleEvent(provider::ServerLifecycleEvent event);
|
||||
|
||||
// 判断是否需要同步处理
|
||||
bool RequiresSyncProcessing(const std::string& method) const;
|
||||
|
|
@ -50,7 +50,7 @@ namespace lsp::core
|
|||
private:
|
||||
RequestDispatcher dispatcher_;
|
||||
scheduler::Request request_scheduler_;
|
||||
service::Container service_container_;
|
||||
service::Registry service_registry_;
|
||||
|
||||
std::atomic<bool> is_initialized_ = false;
|
||||
std::atomic<bool> is_shutting_down_ = false;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,297 @@
|
|||
#include "./keyword_manager.hpp"
|
||||
|
||||
namespace tsl
|
||||
{
|
||||
KeywordManager& KeywordManager::GetInstance()
|
||||
{
|
||||
static KeywordManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
KeywordManager::KeywordManager()
|
||||
{
|
||||
InitKeywords();
|
||||
}
|
||||
|
||||
std::vector<KeywordInfo> KeywordManager::GetAllKeywords()
|
||||
{
|
||||
std::vector<KeywordInfo> keyword;
|
||||
keyword.reserve(keywords_.size());
|
||||
for (const auto& [key, value] : keywords_)
|
||||
keyword.push_back(value);
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::vector<KeywordInfo> KeywordManager::GetKeyWordByPrefix(std::string prefix)
|
||||
{
|
||||
std::vector<KeywordInfo> keyword;
|
||||
for (const auto& [key, value] : keywords_)
|
||||
{
|
||||
if (key.starts_with(prefix))
|
||||
keyword.push_back(value);
|
||||
}
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::optional<KeywordInfo> KeywordManager::GetKeywordInfo(std::string key)
|
||||
{
|
||||
auto target = keywords_.find(key);
|
||||
if (target == keywords_.end())
|
||||
return std::nullopt;
|
||||
return target->second;
|
||||
}
|
||||
|
||||
void KeywordManager::InitKeywords()
|
||||
{
|
||||
keywords_.reserve(200);
|
||||
|
||||
InitProgramStructureKeywords();
|
||||
InitDataTypeKeywords();
|
||||
InitClassKeywords();
|
||||
InitControlFlowKeywords();
|
||||
InitOperatorKeywords();
|
||||
InitSqlKeywords();
|
||||
InitBuiltinKeywords();
|
||||
InitConstantKeywords();
|
||||
}
|
||||
|
||||
void KeywordManager::InitProgramStructureKeywords()
|
||||
{
|
||||
keywords_["program"] = {
|
||||
"program",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Program\n\n程序开始的入口,一般用户不需要使用,在作为独立的TSL脚本时可以使用。 \n通常来说,倘若编写TSL代码作为CGI执行运行,系统默认以PROGRAM模式运行。虽然TSL可以省略PROGRAM关键字,但是使用PROGRAM关键字可以使得TSL代码里包含子函数.\n\n**例如:**\n```pascal\nprogram Test;\n\tfunction sub1();\n\tbegin\n\t\twriteln('Execute sub1');\n\tend;\nbegin\n\tsub1();\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["function"] = {
|
||||
"function",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Function\n\n函数声明开始,组成类似于FUNCTION XXXX(); BEGIN END;的函数块"
|
||||
};
|
||||
|
||||
keywords_["procedure"] = {
|
||||
"procedure",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Procedure\n\n与FUNCTION类似,但是在函数头后不允许加返回类型值"
|
||||
};
|
||||
|
||||
keywords_["unit"] = {
|
||||
"unit",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Unit Declaration\n\nDeclares a code unit/module.\n\n**Syntax:**\n```pascal\nunit UnitName;\ninterface\n // public declarations\nimplementation\n // private implementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["uses"] = {
|
||||
"uses",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Uses Clause\n\nImports external units/modules.\n\n**Syntax:**\n```pascal\nuses Unit1, Unit2, Unit3;\n```\n\n**Example:**\n```pascal\nuses System, SysUtils, Classes;\n```"
|
||||
};
|
||||
|
||||
keywords_["implementation"] = {
|
||||
"implementation",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Implementation Section\n\nMarks the beginning of the private implementation section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public interface\nimplementation\n // private implementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["interface"] = {
|
||||
"interface",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Interface Section\n\nMarks the public interface section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public declarations\n function PublicFunction: integer;\nimplementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["initialization"] = {
|
||||
"initialization",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Initialization Section\n\nCode executed when the unit is first loaded.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // initialization code\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["finalization"] = {
|
||||
"finalization",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Finalization Section\n\nCode executed when the program terminates.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // setup code\nfinalization\n // cleanup code\nend.\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitDataTypeKeywords()
|
||||
{
|
||||
keywords_["string"] = {
|
||||
"string",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## String Type\n\nVariable-length string data type.\n\n**Example:**\n```pascal\nvar\n myString: string;\nbegin\n myString := 'Hello World';\nend;\n```\n\n**Note:** Supports Unicode and automatic memory management."
|
||||
};
|
||||
|
||||
keywords_["integer"] = {
|
||||
"integer",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Integer Type\n\n32-bit signed integer data type.\n\n**Range:** -2,147,483,648 to 2,147,483,647\n\n**Example:**\n```pascal\nvar\n count: integer;\nbegin\n count := 42;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["boolean"] = {
|
||||
"boolean",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Boolean Type\n\nLogical data type with values `true` or `false`.\n\n**Example:**\n```pascal\nvar\n isValid: boolean;\nbegin\n isValid := true;\n if isValid then\n echo('Valid!');\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["int64"] = {
|
||||
"int64",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Int64 Type\n\n64-bit signed integer data type.\n\n**Range:** -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807\n\n**Example:**\n```pascal\nvar\n bigNumber: int64;\nbegin\n bigNumber := 1234567890123456789;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["real"] = {
|
||||
"real",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Real Type\n\nFloating-point number data type.\n\n**Example:**\n```pascal\nvar\n price: real;\nbegin\n price := 19.99;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["array"] = {
|
||||
"array",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Array Type\n\nCollection of elements of the same type.\n\n**Syntax:**\n```pascal\narray[IndexType] of ElementType\n```\n\n**Examples:**\n```pascal\nvar\n numbers: array[1..10] of integer;\n names: array of string; // dynamic array\nbegin\n numbers[1] := 42;\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitClassKeywords()
|
||||
{
|
||||
keywords_["type"] = {
|
||||
"type",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## Type Declaration\n\nDeclares custom data types.\n\n**Syntax:**\n```pascal\ntype\n TypeName = TypeDefinition;\n```\n\n**Example:**\n```pascal\ntype\n TPoint = record\n X, Y: integer;\n end;\n \n TMyClass = class\n // class members\n end;\n```"
|
||||
};
|
||||
|
||||
keywords_["class"] = {
|
||||
"class",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## Class Declaration\n\nDeclares an object-oriented class.\n\n**Syntax:**\n```pascal\ntype\n TClassName = class(TBaseClass)\n private\n // private members\n public\n // public members\n end;\n```\n\n**Example:**\n```pascal\ntype\n TPerson = class\n private\n FName: string;\n public\n constructor Create(AName: string);\n property Name: string read FName write FName;\n end;\n```"
|
||||
};
|
||||
|
||||
keywords_["new"] = {
|
||||
"new",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## New Instance\n\nCreates a new instance of a class.\n\n**Syntax:**\n```pascal\nInstanceVar := ClassName.Create();\n```\n\n**Example:**\n```pascal\nvar\n person: TPerson;\nbegin\n person := TPerson.Create('John');\n try\n // use person\n finally\n person.Free;\n end;\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitControlFlowKeywords()
|
||||
{
|
||||
keywords_["if"] = {
|
||||
"if",
|
||||
KeywordCategory::kConditionals,
|
||||
"## If Statement\n\nConditional execution based on a boolean expression.\n\n**Syntax:**\n```pascal\nif condition then\n statement\nelse\n statement;\n```\n\n**Example:**\n```pascal\nif age >= 18 then\n echo('Adult')\nelse\n echo('Minor');\n```\n\n**Multi-line:**\n```pascal\nif score >= 90 then\nbegin\n grade := 'A';\n echo('Excellent!');\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["for"] = {
|
||||
"for",
|
||||
KeywordCategory::kLoops,
|
||||
"## For Loop\n\nIterates over a range of values.\n\n**Syntax:**\n```pascal\nfor variable := startValue to endValue do\n statement;\n \nfor variable := startValue downto endValue do\n statement;\n```\n\n**Examples:**\n```pascal\n// Forward loop\nfor i := 1 to 10 do\n echo(i);\n \n// Reverse loop\nfor i := 10 downto 1 do\n echo(i);\n \n// Array iteration\nfor i := Low(myArray) to High(myArray) do\n echo(myArray[i]);\n```"
|
||||
};
|
||||
|
||||
keywords_["while"] = {
|
||||
"while",
|
||||
KeywordCategory::kLoops,
|
||||
"## While Loop\n\nRepeats while a condition is true.\n\n**Syntax:**\n```pascal\nwhile condition do\n statement;\n```\n\n**Example:**\n```pascal\ni := 0;\nwhile i < 10 do\nbegin\n echo(i);\n i := i + 1;\nend;\n```\n\n**Note:** The condition is checked before each iteration."
|
||||
};
|
||||
|
||||
keywords_["case"] = {
|
||||
"case",
|
||||
KeywordCategory::kConditionals,
|
||||
"## Case Statement\n\nMulti-way conditional based on value matching.\n\n**Syntax:**\n```pascal\ncase expression of\n value1: statement1;\n value2: statement2;\n else\n defaultStatement;\nend;\n```\n\n**Example:**\n```pascal\ncase dayOfWeek of\n 1: echo('Monday');\n 2: echo('Tuesday');\n 3: echo('Wednesday');\n 4: echo('Thursday');\n 5: echo('Friday');\n 6, 7: echo('Weekend');\n else\n echo('Invalid day');\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitOperatorKeywords()
|
||||
{
|
||||
keywords_["and"] = {
|
||||
"and",
|
||||
KeywordCategory::kLogicalOperators,
|
||||
"## Logical AND\n\nLogical conjunction operator.\n\n**Truth Table:**\n| A | B | A and B |\n|---|---|--------|\n| T | T | T |\n| T | F | F |\n| F | T | F |\n| F | F | F |\n\n**Example:**\n```pascal\nif (age >= 18) and (hasLicense) then\n echo('Can drive');\n```"
|
||||
};
|
||||
|
||||
keywords_["or"] = {
|
||||
"or",
|
||||
KeywordCategory::kLogicalOperators,
|
||||
"## Logical OR\n\nLogical disjunction operator.\n\n**Truth Table:**\n| A | B | A or B |\n|---|---|-------|\n| T | T | T |\n| T | F | T |\n| F | T | T |\n| F | F | F |\n\n**Example:**\n```pascal\nif (isAdmin) or (isOwner) then\n echo('Has permission');\n```"
|
||||
};
|
||||
|
||||
keywords_["div"] = {
|
||||
"div",
|
||||
KeywordCategory::kArithmeticOperators,
|
||||
"## Integer Division\n\nPerforms integer division (truncates decimal part).\n\n**Example:**\n```pascal\nvar result: integer;\nbegin\n result := 17 div 5; // result = 3\n result := 20 div 4; // result = 5\nend;\n```\n\n**Note:** Use `/` for real division, `div` for integer division."
|
||||
};
|
||||
|
||||
keywords_["mod"] = {
|
||||
"mod",
|
||||
KeywordCategory::kArithmeticOperators,
|
||||
"## Modulo Operator\n\nReturns the remainder of integer division.\n\n**Example:**\n```pascal\nvar remainder: integer;\nbegin\n remainder := 17 mod 5; // remainder = 2\n remainder := 20 mod 4; // remainder = 0\n \n // Check if number is even\n if (number mod 2) = 0 then\n echo('Even number');\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitSqlKeywords()
|
||||
{
|
||||
keywords_["select"] = {
|
||||
"select",
|
||||
KeywordCategory::kSqlControl,
|
||||
"## SQL SELECT Statement\n\nRetrieves data from database tables.\n\n**Syntax:**\n```sql\nSELECT column1, column2, ...\nFROM table_name\nWHERE condition\nORDER BY column;\n```\n\n**Examples:**\n```sql\n-- Basic select\nSELECT name, age FROM users;\n\n-- With condition\nSELECT * FROM products WHERE price > 100;\n\n-- With ordering\nSELECT name, salary FROM employees ORDER BY salary DESC;\n```"
|
||||
};
|
||||
|
||||
keywords_["update"] = {
|
||||
"update",
|
||||
KeywordCategory::kSqlControl,
|
||||
"## SQL UPDATE Statement\n\nModifies existing records in a table.\n\n**Syntax:**\n```sql\nUPDATE table_name\nSET column1 = value1, column2 = value2, ...\nWHERE condition;\n```\n\n**Examples:**\n```sql\n-- Update single record\nUPDATE users SET age = 30 WHERE id = 1;\n\n-- Update multiple columns\nUPDATE products \nSET price = 99.99, category = 'Electronics'\nWHERE id = 100;\n```\n\n**⚠️ Warning:** Always use WHERE clause to avoid updating all records!"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitBuiltinKeywords()
|
||||
{
|
||||
keywords_["echo"] = {
|
||||
"echo",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Echo Function\n\nOutputs text to the console or output stream.\n\n**Syntax:**\n```pascal\necho(expression);\necho(format, args...);\n```\n\n**Examples:**\n```pascal\necho('Hello World!');\necho('Number: ', 42);\necho('Name: %s, Age: %d', name, age);\n```\n\n**Features:**\n- Supports multiple arguments\n- Automatic type conversion\n- Format string support"
|
||||
};
|
||||
|
||||
keywords_["mtic"] = {
|
||||
"mtic",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Timer Start (mtic)\n\nStarts a high-precision timer for performance measurement.\n\n**Usage:**\n```pascal\nmtic(); // Start timer\n// ... code to measure ...\nvar elapsed := mtoc(); // Get elapsed time\necho('Elapsed: ', elapsed, ' seconds');\n```\n\n**Note:** Use with `mtoc()` to measure execution time."
|
||||
};
|
||||
|
||||
keywords_["mtoc"] = {
|
||||
"mtoc",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Timer End (mtoc)\n\nReturns elapsed time since last `mtic()` call.\n\n**Returns:** Time in seconds (real number)\n\n**Example:**\n```pascal\nmtic();\nfor i := 1 to 1000000 do\n // some computation\nvar timeElapsed := mtoc();\necho('Loop took: ', timeElapsed, ' seconds');\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitConstantKeywords()
|
||||
{
|
||||
keywords_["true"] = {
|
||||
"true",
|
||||
KeywordCategory::kBooleanConstants,
|
||||
"## Boolean True\n\nRepresents the boolean value **true**.\n\n**Usage:**\n```pascal\nvar\n flag: boolean;\nbegin\n flag := true;\n \n if flag then\n echo('Flag is set!');\nend;\n```\n\n**Note:** Case-insensitive in most Pascal dialects."
|
||||
};
|
||||
|
||||
keywords_["false"] = {
|
||||
"false",
|
||||
KeywordCategory::kBooleanConstants,
|
||||
"## Boolean False\n\nRepresents the boolean value **false**.\n\n**Usage:**\n```pascal\nvar\n isComplete: boolean;\nbegin\n isComplete := false;\n \n while not isComplete do\n begin\n // do work\n isComplete := checkCompletion();\n end;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["nil"] = {
|
||||
"nil",
|
||||
KeywordCategory::kNullConstants,
|
||||
"## Nil Constant\n\nRepresents a null/empty pointer or object reference.\n\n**Usage:**\n```pascal\nvar\n obj: TMyClass;\nbegin\n obj := nil; // Initialize to null\n \n if obj <> nil then\n obj.DoSomething();\n \n obj := TMyClass.Create();\n try\n // use obj\n finally\n obj.Free;\n obj := nil; // Clear reference\n end;\nend;\n```\n\n**Best Practice:** Always check for nil before using object references."
|
||||
};
|
||||
|
||||
keywords_["inf"] = {
|
||||
"inf",
|
||||
KeywordCategory::kMathConstants,
|
||||
"## Infinity Constant\n\nRepresents positive mathematical infinity.\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := 1.0 / 0.0; // Results in inf\n \n if result = inf then\n echo('Result is infinite');\nend;\n```\n\n**Note:** Use for floating-point calculations and comparisons."
|
||||
};
|
||||
|
||||
keywords_["nan"] = {
|
||||
"nan",
|
||||
KeywordCategory::kMathConstants,
|
||||
"## Not a Number (NaN)\n\nRepresents an undefined or invalid floating-point result.\n\n**Common Causes:**\n- `0.0 / 0.0`\n- `sqrt(-1.0)`\n- `inf - inf`\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := sqrt(-1.0); // Results in NaN\n \n if IsNaN(result) then\n echo('Invalid calculation');\nend;\n```\n\n**Note:** NaN ≠ NaN, use `IsNaN()` function for checking."
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "./keyword_types.hpp"
|
||||
|
||||
namespace tsl
|
||||
{
|
||||
class KeywordManager
|
||||
{
|
||||
public:
|
||||
KeywordManager(const KeywordManager&) = delete;
|
||||
KeywordManager& operator=(const KeywordManager&) = delete;
|
||||
|
||||
static KeywordManager& GetInstance();
|
||||
std::vector<KeywordInfo> GetAllKeywords();
|
||||
std::vector<KeywordInfo> GetKeyWordByPrefix(std::string prefix);
|
||||
std::optional<KeywordInfo> GetKeywordInfo(std::string key);
|
||||
|
||||
private:
|
||||
KeywordManager();
|
||||
void InitKeywords();
|
||||
|
||||
void InitProgramStructureKeywords();
|
||||
void InitDataTypeKeywords();
|
||||
void InitClassKeywords();
|
||||
void InitControlFlowKeywords();
|
||||
void InitOperatorKeywords();
|
||||
void InitSqlKeywords();
|
||||
void InitBuiltinKeywords();
|
||||
void InitConstantKeywords();
|
||||
|
||||
std::unordered_map<std::string, KeywordInfo> keywords_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
#include "../protocol/protocol.hpp"
|
||||
|
||||
namespace tsl
|
||||
|
|
@ -40,32 +39,11 @@ namespace tsl
|
|||
kNullConstants // nil
|
||||
};
|
||||
|
||||
// 关键字信息
|
||||
struct KeywordInfo
|
||||
{
|
||||
std::string keyword;
|
||||
KeywordCategory category;
|
||||
std::string description;
|
||||
lsp::protocol::CompletionItemKind completion_kind;
|
||||
};
|
||||
|
||||
class TslKeywords
|
||||
{
|
||||
public:
|
||||
static const std::vector<KeywordInfo>& GetAllKeywords();
|
||||
static std::vector<KeywordInfo> GetKeywordsByCategory(KeywordCategory category);
|
||||
static std::vector<lsp::protocol::CompletionItem> GetCompletionItems(const std::string& prefix = "");
|
||||
static bool IsKeyword(const std::string& word);
|
||||
static KeywordCategory GetKeywordCategory(const std::string& word);
|
||||
|
||||
private:
|
||||
static void InitKeywords();
|
||||
static std::string ToLowerCase(const std::string& str);
|
||||
static bool StartsWith(const std::string& str, const std::string& prefix);
|
||||
|
||||
private:
|
||||
static std::vector<KeywordInfo> keywords_;
|
||||
static std::unordered_set<std::string> keyword_set_;
|
||||
static bool initialized_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,281 +0,0 @@
|
|||
#include <vector>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include "./tsl_keywords.hpp"
|
||||
|
||||
namespace tsl
|
||||
{
|
||||
std::vector<KeywordInfo> TslKeywords::keywords_;
|
||||
std::unordered_set<std::string> TslKeywords::keyword_set_;
|
||||
bool TslKeywords::initialized_ = false;
|
||||
|
||||
const std::vector<KeywordInfo>& TslKeywords::GetAllKeywords()
|
||||
{
|
||||
InitKeywords();
|
||||
return keywords_;
|
||||
}
|
||||
|
||||
std::vector<KeywordInfo> TslKeywords::GetKeywordsByCategory(KeywordCategory category)
|
||||
{
|
||||
InitKeywords();
|
||||
std::vector<KeywordInfo> result;
|
||||
|
||||
for (const auto& keyword : keywords_)
|
||||
if (keyword.category == category)
|
||||
result.push_back(keyword);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<lsp::protocol::CompletionItem> TslKeywords::GetCompletionItems(const std::string& prefix)
|
||||
{
|
||||
InitKeywords();
|
||||
std::vector<lsp::protocol::CompletionItem> result;
|
||||
std::string lower_prefix = ToLowerCase(prefix);
|
||||
|
||||
for (const auto& keyword : keywords_)
|
||||
{
|
||||
if (prefix.empty() || StartsWith(ToLowerCase(keyword.keyword), lower_prefix))
|
||||
{
|
||||
lsp::protocol::CompletionItem item;
|
||||
item.label = keyword.keyword;
|
||||
item.kind = keyword.completion_kind;
|
||||
item.detail = keyword.description;
|
||||
item.insertText = keyword.keyword;
|
||||
result.push_back(item);
|
||||
}
|
||||
}
|
||||
// 按字母顺序排序
|
||||
std::sort(result.begin(), result.end(),
|
||||
[](const lsp::protocol::CompletionItem& a, const lsp::protocol::CompletionItem& b) {
|
||||
return a.label < b.label;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
KeywordCategory TslKeywords::GetKeywordCategory(const std::string& word)
|
||||
{
|
||||
InitKeywords();
|
||||
std::string lower_word = ToLowerCase(word);
|
||||
|
||||
for (const auto& keyword : keywords_)
|
||||
{
|
||||
if (ToLowerCase(keyword.keyword) == lower_word) {
|
||||
return keyword.category;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没找到,返回一个默认值(可以考虑抛出异常)
|
||||
return KeywordCategory::kProgramStructure;
|
||||
}
|
||||
|
||||
void TslKeywords::InitKeywords()
|
||||
{
|
||||
if (initialized_)
|
||||
return;
|
||||
keywords_ = {
|
||||
// Program Structure
|
||||
{ "program", KeywordCategory::kProgramStructure, "Program declaration", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "function", KeywordCategory::kProgramStructure, "Function declaration", lsp::protocol::CompletionItemKind::kFunction },
|
||||
{ "procedure", KeywordCategory::kProgramStructure, "Procedure declaration", lsp::protocol::CompletionItemKind::kFunction },
|
||||
{ "unit", KeywordCategory::kProgramStructure, "Unit declaration", lsp::protocol::CompletionItemKind::kModule },
|
||||
{ "uses", KeywordCategory::kProgramStructure, "Uses clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "implementation", KeywordCategory::kProgramStructure, "Implementation section", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "interface", KeywordCategory::kProgramStructure, "Interface section", lsp::protocol::CompletionItemKind::kInterface },
|
||||
{ "initialization", KeywordCategory::kProgramStructure, "Initialization section", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "finalization", KeywordCategory::kProgramStructure, "Finalization section", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Data Types
|
||||
{ "string", KeywordCategory::kDataTypes, "String data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "integer", KeywordCategory::kDataTypes, "Integer data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "boolean", KeywordCategory::kDataTypes, "Boolean data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "int64", KeywordCategory::kDataTypes, "64-bit integer data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "real", KeywordCategory::kDataTypes, "Real number data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "array", KeywordCategory::kDataTypes, "Array data type", lsp::protocol::CompletionItemKind::kClass },
|
||||
|
||||
// Class Types
|
||||
{ "type", KeywordCategory::kClassTypes, "Type declaration", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "class", KeywordCategory::kClassTypes, "Class declaration", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "fakeclass", KeywordCategory::kClassTypes, "Fake class declaration", lsp::protocol::CompletionItemKind::kClass },
|
||||
{ "new", KeywordCategory::kClassTypes, "Object instantiation", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Class Modifiers
|
||||
{ "override", KeywordCategory::kClassModifiers, "Override method", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "overload", KeywordCategory::kClassModifiers, "Overload method", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "virtual", KeywordCategory::kClassModifiers, "Virtual method", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "property", KeywordCategory::kClassModifiers, "Property declaration", lsp::protocol::CompletionItemKind::kProperty },
|
||||
{ "self", KeywordCategory::kClassModifiers, "Self reference", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "inherited", KeywordCategory::kClassModifiers, "Inherited method call", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Access Modifiers
|
||||
{ "public", KeywordCategory::kAccessModifiers, "Public access modifier", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "protected", KeywordCategory::kAccessModifiers, "Protected access modifier", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "private", KeywordCategory::kAccessModifiers, "Private access modifier", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "published", KeywordCategory::kAccessModifiers, "Published access modifier", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Property Accessors
|
||||
{ "read", KeywordCategory::kPropertyAccessors, "Property read accessor", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "write", KeywordCategory::kPropertyAccessors, "Property write accessor", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Constructors
|
||||
{ "create", KeywordCategory::kConstructors, "Constructor method", lsp::protocol::CompletionItemKind::kConstructor },
|
||||
{ "destroy", KeywordCategory::kConstructors, "Destructor method", lsp::protocol::CompletionItemKind::kMethod },
|
||||
{ "operator", KeywordCategory::kConstructors, "Operator overload", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// Variable Modifiers
|
||||
{ "external", KeywordCategory::kVariableModifiers, "External declaration", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "const", KeywordCategory::kVariableModifiers, "Constant declaration", lsp::protocol::CompletionItemKind::kConstant },
|
||||
{ "out", KeywordCategory::kVariableModifiers, "Output parameter", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "var", KeywordCategory::kVariableModifiers, "Variable declaration", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "global", KeywordCategory::kVariableModifiers, "Global variable", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "static", KeywordCategory::kVariableModifiers, "Static variable", lsp::protocol::CompletionItemKind::kVariable },
|
||||
|
||||
// Conditionals
|
||||
{ "if", KeywordCategory::kConditionals, "If statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "else", KeywordCategory::kConditionals, "Else clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "then", KeywordCategory::kConditionals, "Then clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "case", KeywordCategory::kConditionals, "Case statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "of", KeywordCategory::kConditionals, "Of clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Loops
|
||||
{ "for", KeywordCategory::kLoops, "For loop", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "while", KeywordCategory::kLoops, "While loop", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "do", KeywordCategory::kLoops, "Do clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "downto", KeywordCategory::kLoops, "Downto clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "step", KeywordCategory::kLoops, "Step clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "until", KeywordCategory::kLoops, "Until clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "repeat", KeywordCategory::kLoops, "Repeat loop", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "to", KeywordCategory::kLoops, "To clause", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Branch Control
|
||||
{ "break", KeywordCategory::kBranchControl, "Break statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "continue", KeywordCategory::kBranchControl, "Continue statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "goto", KeywordCategory::kBranchControl, "Goto statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "label", KeywordCategory::kBranchControl, "Label declaration", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "exit", KeywordCategory::kBranchControl, "Exit statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Return Control
|
||||
{ "return", KeywordCategory::kReturnControl, "Return statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "debugreturn", KeywordCategory::kReturnControl, "Debug return statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "debugrunenv", KeywordCategory::kReturnControl, "Debug run environment", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "debugrunenvdo", KeywordCategory::kReturnControl, "Debug run environment do", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Block Control
|
||||
{ "begin", KeywordCategory::kBlockControl, "Begin block", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "end", KeywordCategory::kBlockControl, "End block", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "with", KeywordCategory::kBlockControl, "With statement", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// References
|
||||
{ "weakref", KeywordCategory::kReferences, "Weak reference", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "autoref", KeywordCategory::kReferences, "Auto reference", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Namespace
|
||||
{ "namespace", KeywordCategory::kNamespace, "Namespace declaration", lsp::protocol::CompletionItemKind::kModule },
|
||||
|
||||
// Exceptions
|
||||
{ "except", KeywordCategory::kExceptions, "Exception handling", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "raise", KeywordCategory::kExceptions, "Raise exception", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "try", KeywordCategory::kExceptions, "Try block", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "finally", KeywordCategory::kExceptions, "Finally block", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "exceptobject", KeywordCategory::kExceptions, "Exception object", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Logical Operators
|
||||
{ "and", KeywordCategory::kLogicalOperators, "Logical AND", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "in", KeywordCategory::kLogicalOperators, "In operator", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "is", KeywordCategory::kLogicalOperators, "Is operator", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "not", KeywordCategory::kLogicalOperators, "Logical NOT", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "or", KeywordCategory::kLogicalOperators, "Logical OR", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// Arithmetic Operators
|
||||
{ "div", KeywordCategory::kArithmeticOperators, "Integer division", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "mod", KeywordCategory::kArithmeticOperators, "Modulo operation", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// Bitwise Operators
|
||||
{ "ror", KeywordCategory::kBitwiseOperators, "Rotate right", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "rol", KeywordCategory::kBitwiseOperators, "Rotate left", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "shr", KeywordCategory::kBitwiseOperators, "Shift right", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "shl", KeywordCategory::kBitwiseOperators, "Shift left", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// Set Operators
|
||||
{ "union", KeywordCategory::kSetOperators, "Set union", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "minus", KeywordCategory::kSetOperators, "Set difference", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "union2", KeywordCategory::kSetOperators, "Set union (alternative)", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// SQL Control
|
||||
{ "select", KeywordCategory::kSqlControl, "SQL SELECT", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "vselect", KeywordCategory::kSqlControl, "Virtual SELECT", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "sselect", KeywordCategory::kSqlControl, "Special SELECT", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "update", KeywordCategory::kSqlControl, "SQL UPDATE", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "delete", KeywordCategory::kSqlControl, "SQL DELETE", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "mselect", KeywordCategory::kSqlControl, "Multiple SELECT", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// SQL Keywords
|
||||
{ "sqlin", KeywordCategory::kSqlKeywords, "SQL IN", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "from", KeywordCategory::kSqlKeywords, "SQL FROM", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "where", KeywordCategory::kSqlKeywords, "SQL WHERE", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "group", KeywordCategory::kSqlKeywords, "SQL GROUP", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "by", KeywordCategory::kSqlKeywords, "SQL BY", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "order", KeywordCategory::kSqlKeywords, "SQL ORDER", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "distinct", KeywordCategory::kSqlKeywords, "SQL DISTINCT", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "join", KeywordCategory::kSqlKeywords, "SQL JOIN", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// SQL Operators (note: some overlap with logical operators)
|
||||
{ "on", KeywordCategory::kSqlOperators, "SQL ON", lsp::protocol::CompletionItemKind::kOperator },
|
||||
{ "like", KeywordCategory::kSqlOperators, "SQL LIKE", lsp::protocol::CompletionItemKind::kOperator },
|
||||
|
||||
// Calling Conventions
|
||||
{ "cdecl", KeywordCategory::kCallingConventions, "C calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "pascal", KeywordCategory::kCallingConventions, "Pascal calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "stdcall", KeywordCategory::kCallingConventions, "Standard calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "safecall", KeywordCategory::kCallingConventions, "Safe calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "fastcall", KeywordCategory::kCallingConventions, "Fast calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "register", KeywordCategory::kCallingConventions, "Register calling convention", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// System Keywords
|
||||
{ "setuid", KeywordCategory::kSystemKeywords, "Set user ID", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
{ "sudo", KeywordCategory::kSystemKeywords, "Super user do", lsp::protocol::CompletionItemKind::kKeyword },
|
||||
|
||||
// Builtin Variables
|
||||
{ "paramcount", KeywordCategory::kBuiltinVariables, "Parameter count", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "realparamcount", KeywordCategory::kBuiltinVariables, "Real parameter count", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "params", KeywordCategory::kBuiltinVariables, "Parameters array", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "system", KeywordCategory::kBuiltinVariables, "System variable", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "tslassigning", KeywordCategory::kBuiltinVariables, "TSL assigning", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "likeeps", KeywordCategory::kBuiltinVariables, "Like EPS", lsp::protocol::CompletionItemKind::kVariable },
|
||||
{ "likeepsrate", KeywordCategory::kBuiltinVariables, "Like EPS rate", lsp::protocol::CompletionItemKind::kVariable },
|
||||
|
||||
// Builtin Functions
|
||||
{ "echo", KeywordCategory::kBuiltinFunctions, "Echo function", lsp::protocol::CompletionItemKind::kFunction },
|
||||
{ "mtic", KeywordCategory::kBuiltinFunctions, "MTIC function", lsp::protocol::CompletionItemKind::kFunction },
|
||||
{ "mtoc", KeywordCategory::kBuiltinFunctions, "MTOC function", lsp::protocol::CompletionItemKind::kFunction },
|
||||
|
||||
// Boolean Constants
|
||||
{ "false", KeywordCategory::kBooleanConstants, "Boolean false", lsp::protocol::CompletionItemKind::kConstant },
|
||||
{ "true", KeywordCategory::kBooleanConstants, "Boolean true", lsp::protocol::CompletionItemKind::kConstant },
|
||||
|
||||
// Math Constants
|
||||
{ "inf", KeywordCategory::kMathConstants, "Infinity", lsp::protocol::CompletionItemKind::kConstant },
|
||||
{ "nan", KeywordCategory::kMathConstants, "Not a Number", lsp::protocol::CompletionItemKind::kConstant },
|
||||
|
||||
// Null Constants
|
||||
{ "nil", KeywordCategory::kNullConstants, "Null value", lsp::protocol::CompletionItemKind::kConstant }
|
||||
};
|
||||
keyword_set_.clear();
|
||||
for (const auto& keyword : keywords_)
|
||||
keyword_set_.insert(ToLowerCase(keyword.keyword));
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
std::string TslKeywords::ToLowerCase(const std::string& str)
|
||||
{
|
||||
std::string result = str;
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TslKeywords::StartsWith(const std::string& str, const std::string& prefix)
|
||||
{
|
||||
if (prefix.length() > str.length())
|
||||
return false;
|
||||
return str.compare(0, prefix.length(), prefix) == 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
lsp::utils::ServerConfig config = lsp::utils::ArgsParser::Parse(argc, argv);
|
||||
lsp::utils::ArgsParser& args_parser = lsp::utils::ArgsParser::GetInstance();
|
||||
auto& config = args_parser.Parse(argc, argv);
|
||||
|
||||
if (config.show_help)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace lsp::protocol
|
|||
|
||||
struct VersionedTextDocumentIdentifier : TextDocumentIdentifier
|
||||
{
|
||||
std::optional<integer> version;
|
||||
integer version;
|
||||
};
|
||||
|
||||
struct OptionalVersionedTextDocumentIdentifier : TextDocumentIdentifier
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,18 +1,20 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include "./provider_registry.hpp"
|
||||
#include "../initialize/initialize.hpp"
|
||||
#include "../initialized/initialized.hpp"
|
||||
#include "../text_document/did_open.hpp"
|
||||
#include "../text_document/did_change.hpp"
|
||||
#include "../text_document/did_close.hpp"
|
||||
#include "../text_document/completion.hpp"
|
||||
#include "../text_document/semantic_tokens.hpp"
|
||||
// #include "../text_document/semantic_tokens.hpp"
|
||||
#include "../trace/set_trace.hpp"
|
||||
#include "../shutdown/shutdown.hpp"
|
||||
#include "../cancel_request/cancel_request.hpp"
|
||||
#include "../exit/exit.hpp"
|
||||
#include "../completion_item/resolve.hpp"
|
||||
#include "./registry.hpp"
|
||||
#include "./bootstrap.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
void RegisterAllProviders(core::RequestDispatcher& dispatcher)
|
||||
|
|
@ -25,9 +27,10 @@ namespace lsp::providers
|
|||
RegisterProvider<text_document::DidChange>(dispatcher);
|
||||
RegisterProvider<text_document::DidClose>(dispatcher);
|
||||
RegisterProvider<text_document::Completion>(dispatcher);
|
||||
RegisterProvider<text_document::SemanticTokensRange>(dispatcher);
|
||||
RegisterProvider<text_document::SemanticTokensFull>(dispatcher);
|
||||
RegisterProvider<text_document::SemanticTokensFullDelta>(dispatcher);
|
||||
// RegisterProvider<text_document::SemanticTokensRange>(dispatcher);
|
||||
// RegisterProvider<text_document::SemanticTokensFull>(dispatcher);
|
||||
// RegisterProvider<text_document::SemanticTokensFullDelta>(dispatcher);
|
||||
RegisterProvider<completion_item::Resolve>(dispatcher);
|
||||
RegisterProvider<SetTrace>(dispatcher);
|
||||
RegisterProvider<Shutdown>(dispatcher);
|
||||
RegisterProvider<CancelRequest>(dispatcher);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "../../core/dispacther.hpp"
|
||||
|
||||
namespace lsp::provider
|
||||
{
|
||||
// 批量注册provider
|
||||
void RegisterAllProviders(core::RequestDispatcher& dispatcher);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "./provider_interface.hpp"
|
||||
#include "./interface.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message)
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
#include <string>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "../../scheduler/request.hpp"
|
||||
#include "../../service/base/container.hpp"
|
||||
#include "../../service/base/registry.hpp"
|
||||
#include "../../protocol/protocol.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
enum class ServerLifecycleEvent
|
||||
{
|
||||
|
|
@ -21,15 +21,15 @@ namespace lsp::providers
|
|||
class ExecutionContext
|
||||
{
|
||||
public:
|
||||
ExecutionContext(LifecycleCallback lifecycle_callback, scheduler::Request& scheduler, service::Container& container) :
|
||||
lifecycle_callback_(lifecycle_callback), request_scheduler_(scheduler), service_container_(container) {}
|
||||
ExecutionContext(LifecycleCallback lifecycle_callback, scheduler::Request& scheduler, service::Registry& registry) :
|
||||
lifecycle_callback_(lifecycle_callback), request_scheduler_(scheduler), service_registry_(registry) {}
|
||||
|
||||
scheduler::Request& GetScheduler() const { return request_scheduler_; }
|
||||
|
||||
template<typename T>
|
||||
T& GetService() const
|
||||
{
|
||||
return service_container_.GetService<T>();
|
||||
return service_registry_.GetService<T>();
|
||||
}
|
||||
|
||||
void TriggerLifecycleEvent(ServerLifecycleEvent event) const
|
||||
|
|
@ -41,7 +41,7 @@ namespace lsp::providers
|
|||
private:
|
||||
LifecycleCallback lifecycle_callback_;
|
||||
scheduler::Request& request_scheduler_;
|
||||
service::Container& service_container_;
|
||||
service::Registry& service_registry_;
|
||||
};
|
||||
|
||||
// LSP请求提供者接口基类
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include <type_traits>
|
||||
#include "../../core/dispacther.hpp"
|
||||
#include "./provider_interface.hpp"
|
||||
#include "./interface.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
// 注册请求处理器的模板函数
|
||||
template<typename ProviderClass>
|
||||
|
|
@ -26,7 +26,4 @@ namespace lsp::providers
|
|||
spdlog::info("Registered notification provider [{}] for method: [{}]", provider->GetProviderName(), provider->GetMethod());
|
||||
}
|
||||
|
||||
// 批量注册provider
|
||||
void RegisterAllProviders(core::RequestDispatcher& dispatcher);
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./incoming_calls.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::call_hierarchy
|
||||
namespace lsp::provider::call_hierarchy
|
||||
{
|
||||
std::string IncomingCalls::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::call_hierarchy
|
||||
namespace lsp::provider::call_hierarchy
|
||||
{
|
||||
class IncomingCalls : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./outgoing_calls.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::call_hierarchy
|
||||
namespace lsp::provider::call_hierarchy
|
||||
{
|
||||
std::string OutgoingCalls::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::call_hierarchy
|
||||
namespace lsp::provider::call_hierarchy
|
||||
{
|
||||
class OutgoingCalls : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "./cancel_request.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
std::string CancelRequest::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
class CancelRequest : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./register_capability.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::client
|
||||
namespace lsp::provider::client
|
||||
{
|
||||
std::string RegisterCapability::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
#include "../../protocol/protocol.hpp"
|
||||
|
||||
namespace lsp::providers::client
|
||||
namespace lsp::provider::client
|
||||
{
|
||||
class RegisterCapability : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./unregister_capability.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::client
|
||||
namespace lsp::provider::client
|
||||
{
|
||||
std::string UnregisterCapability::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
#include "../../protocol/protocol.hpp"
|
||||
|
||||
namespace lsp::providers::client
|
||||
namespace lsp::provider::client
|
||||
{
|
||||
class UnregisterCapability : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./resolve.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::code_action
|
||||
namespace lsp::provider::code_action
|
||||
{
|
||||
std::string Resolve::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::code_action
|
||||
namespace lsp::provider::code_action
|
||||
{
|
||||
class Resolve : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./resolve.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::code_lens
|
||||
namespace lsp::provider::code_lens
|
||||
{
|
||||
std::string Resolve::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::code_lens
|
||||
namespace lsp::provider::code_lens
|
||||
{
|
||||
class Resolve : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include "./resolve.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
#include "../../language/keyword_manager.hpp"
|
||||
#include "../../service/symbol.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "./resolve.hpp"
|
||||
|
||||
namespace lsp::providers::completion_item
|
||||
namespace lsp::provider::completion_item
|
||||
{
|
||||
std::string Resolve::GetMethod() const
|
||||
{
|
||||
|
|
@ -26,13 +26,9 @@ namespace lsp::providers::completion_item
|
|||
return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInvalidParams, "Missing params");
|
||||
}
|
||||
|
||||
// 解析补全项参数
|
||||
protocol::CompletionItem item = transform::As<protocol::CompletionItem>(request.params.value());
|
||||
|
||||
// 解析补全项,添加详细信息
|
||||
protocol::CompletionItem resolved_item = ResolveCompletionItem(item, context);
|
||||
|
||||
// 构建响应
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.result = transform::LSPAny(resolved_item);
|
||||
|
|
@ -43,279 +39,93 @@ namespace lsp::providers::completion_item
|
|||
return json.value();
|
||||
}
|
||||
|
||||
protocol::CompletionItem Resolve::ResolveCompletionItem(
|
||||
const protocol::CompletionItem& item,
|
||||
ExecutionContext& context)
|
||||
protocol::CompletionItem Resolve::ResolveCompletionItem(const protocol::CompletionItem& item, ExecutionContext& context)
|
||||
{
|
||||
spdlog::trace("{}: Resolving completion item '{}'", GetProviderName(), item.label);
|
||||
|
||||
// 复制原始项
|
||||
protocol::CompletionItem resolved = item;
|
||||
|
||||
// 如果已经有详细信息,直接返回
|
||||
if (resolved.documentation.has_value() && resolved.detail.has_value())
|
||||
if (auto keyword_info = tsl::KeywordManager::GetInstance().GetKeywordInfo(item.label))
|
||||
{
|
||||
spdlog::debug("{}: Item '{}' already resolved", GetProviderName(), item.label);
|
||||
protocol::MarkupContent content;
|
||||
content.kind = protocol::MarkupKindLiterals::Markdown;
|
||||
content.value = keyword_info->description;
|
||||
resolved.documentation = content;
|
||||
}
|
||||
else if (auto symbol_info = context.GetService<service::Symbol>().GetGlobalFunction(item.label))
|
||||
{
|
||||
protocol::MarkupContent content;
|
||||
content.kind = protocol::MarkupKindLiterals::Markdown;
|
||||
std::stringstream ss;
|
||||
ss << "#### from\n\n";
|
||||
ss << symbol_info->file_path << "\n\n";
|
||||
ss << "---\n\n";
|
||||
content.value = ss.str() + GeneratorFunctionMarkdown(symbol_info->symbols[0]);
|
||||
resolved.documentation = content;
|
||||
resolved.insertText = GenerateFunctionSnippet(symbol_info->symbols[0]);
|
||||
resolved.insertTextFormat = protocol::InsertTextFormat::kSnippet;
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
// 根据补全项类型添加详细信息
|
||||
if (!resolved.detail.has_value())
|
||||
{
|
||||
resolved.detail = GetDetailedSignature(item.label,
|
||||
item.kind.value_or(protocol::CompletionItemKind::kText),
|
||||
context);
|
||||
}
|
||||
|
||||
// 添加文档
|
||||
if (!resolved.documentation.has_value())
|
||||
{
|
||||
std::string doc = GetDocumentationForItem(resolved, context);
|
||||
if (!doc.empty())
|
||||
{
|
||||
protocol::MarkupContent markup;
|
||||
markup.kind = protocol::MarkupKindLiterals::Markdown;
|
||||
markup.value = doc;
|
||||
resolved.documentation = markup;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加额外的编辑信息(如自动导入)
|
||||
if (item.kind == protocol::CompletionItemKind::kClass ||
|
||||
item.kind == protocol::CompletionItemKind::kFunction)
|
||||
{
|
||||
// TODO: 检查是否需要添加 uses 语句
|
||||
// 如果符号来自其他单元,可能需要自动添加导入
|
||||
}
|
||||
|
||||
spdlog::info("{}: Resolved item '{}' with {} documentation",
|
||||
GetProviderName(),
|
||||
item.label,
|
||||
resolved.documentation.has_value() ? "added" : "no");
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
std::string Resolve::GetDocumentationForItem(
|
||||
const protocol::CompletionItem& item,
|
||||
ExecutionContext& context)
|
||||
protocol::string Resolve::GeneratorFunctionMarkdown(const service::SymbolInfo& symbol_info)
|
||||
{
|
||||
std::stringstream doc;
|
||||
doc << "#### function\n\n";
|
||||
doc << "`" << symbol_info.name << "`";
|
||||
doc << "\n\n";
|
||||
|
||||
// 根据类型获取文档
|
||||
if (item.kind == protocol::CompletionItemKind::kKeyword)
|
||||
// 参数
|
||||
if (symbol_info.callable && !symbol_info.callable->parameters.empty())
|
||||
{
|
||||
// 关键字文档
|
||||
std::string keyword_doc = GetKeywordDocumentation(item.label);
|
||||
if (!keyword_doc.empty())
|
||||
doc << "##### parameters:\n";
|
||||
for (const auto& param : symbol_info.callable->parameters)
|
||||
{
|
||||
doc << keyword_doc;
|
||||
}
|
||||
}
|
||||
else if (item.kind == protocol::CompletionItemKind::kFunction ||
|
||||
item.kind == protocol::CompletionItemKind::kMethod)
|
||||
{
|
||||
// 函数/方法文档
|
||||
auto builtin_it = kBuiltinFunctions.find(item.label);
|
||||
if (builtin_it != kBuiltinFunctions.end())
|
||||
{
|
||||
doc << builtin_it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 查找用户定义的函数
|
||||
auto symbol = FindSymbolDetails(item.label, context);
|
||||
if (symbol.has_value())
|
||||
{
|
||||
doc << "**" << item.label << "**\n\n";
|
||||
if (symbol->detail.has_value())
|
||||
{
|
||||
doc << "Signature: `" << symbol->detail.value() << "`\n\n";
|
||||
}
|
||||
doc << "User-defined function";
|
||||
}
|
||||
doc << "- `" << param.name << "`";
|
||||
|
||||
// 添加代码示例
|
||||
std::string example = GenerateCodeExample(item.label, *item.kind);
|
||||
if (!example.empty())
|
||||
{
|
||||
doc << "\n\n**Example:**\n```tsf\n"
|
||||
<< example << "\n```";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item.kind == protocol::CompletionItemKind::kClass)
|
||||
{
|
||||
// 类文档
|
||||
auto symbol = FindSymbolDetails(item.label, context);
|
||||
if (symbol.has_value())
|
||||
{
|
||||
doc << "**" << item.label << "** (class)\n\n";
|
||||
|
||||
// 列出公共成员
|
||||
if (!symbol->children.value().empty())
|
||||
{
|
||||
doc << "**Members:**\n";
|
||||
for (const auto& child : symbol->children.value())
|
||||
{
|
||||
if (child.kind == protocol::SymbolKind::kMethod ||
|
||||
child.kind == protocol::SymbolKind::kProperty ||
|
||||
child.kind == protocol::SymbolKind::kField)
|
||||
{
|
||||
doc << "- " << child.name;
|
||||
if (child.detail.has_value())
|
||||
{
|
||||
doc << ": " << child.detail.value();
|
||||
// 类型
|
||||
if (param.typed && !param.typed->type_name.empty())
|
||||
doc << ": `" << param.typed->type_name << "`";
|
||||
doc << "\n";
|
||||
}
|
||||
doc << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item.kind == protocol::CompletionItemKind::kVariable ||
|
||||
item.kind == protocol::CompletionItemKind::kConstant)
|
||||
{
|
||||
// 变量/常量文档
|
||||
auto symbol = FindSymbolDetails(item.label, context);
|
||||
if (symbol.has_value())
|
||||
{
|
||||
doc << "**" << item.label << "**";
|
||||
if (item.kind == protocol::CompletionItemKind::kConstant)
|
||||
{
|
||||
doc << " (constant)";
|
||||
}
|
||||
else
|
||||
{
|
||||
doc << " (variable)";
|
||||
}
|
||||
doc << "\n\n";
|
||||
|
||||
if (symbol->detail.has_value())
|
||||
// 返回值
|
||||
if (symbol_info.callable && symbol_info.callable->return_type)
|
||||
{
|
||||
doc << "Type: `" << symbol->detail.value() << "`";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item.kind == protocol::CompletionItemKind::kSnippet)
|
||||
{
|
||||
// 代码片段文档
|
||||
doc << "**Code Snippet**\n\n";
|
||||
doc << "Inserts a " << item.label << " code structure.\n\n";
|
||||
doc << "Tab through the placeholders to fill in the values.";
|
||||
doc << "##### return\n\n";
|
||||
doc << "`" << *symbol_info.callable->return_type << "`\n\n";
|
||||
}
|
||||
|
||||
return doc.str();
|
||||
}
|
||||
|
||||
std::string Resolve::GetDetailedSignature(const std::string& name, protocol::CompletionItemKind kind, ExecutionContext& context)
|
||||
protocol::string Resolve::GenerateFunctionSnippet(const service::SymbolInfo& symbol_info)
|
||||
{
|
||||
// 尝试从符号服务获取签名
|
||||
auto symbol = FindSymbolDetails(name, context);
|
||||
if (symbol.has_value() && symbol->detail.has_value())
|
||||
std::stringstream snippet;
|
||||
snippet << symbol_info.name << "(";
|
||||
|
||||
if (symbol_info.callable && !symbol_info.callable->parameters.empty())
|
||||
{
|
||||
return symbol->detail.value();
|
||||
}
|
||||
|
||||
// 根据类型生成默认签名
|
||||
switch (kind)
|
||||
const auto& params = symbol_info.callable->parameters;
|
||||
for (size_t i = 0; i < params.size(); ++i)
|
||||
{
|
||||
case protocol::CompletionItemKind::kFunction:
|
||||
return name + "(params): ReturnType";
|
||||
case protocol::CompletionItemKind::kMethod:
|
||||
return name + "(params): ReturnType";
|
||||
case protocol::CompletionItemKind::kClass:
|
||||
return "class " + name;
|
||||
case protocol::CompletionItemKind::kVariable:
|
||||
return name + ": Type";
|
||||
case protocol::CompletionItemKind::kConstant:
|
||||
return "const " + name + " = value";
|
||||
case protocol::CompletionItemKind::kProperty:
|
||||
return "property " + name + ": Type";
|
||||
default:
|
||||
return "";
|
||||
if (i > 0)
|
||||
snippet << ", ";
|
||||
|
||||
// 生成占位符 ${n:param_name}
|
||||
snippet << "${" << (i + 1) << ":";
|
||||
|
||||
// 可选:包含类型提示
|
||||
if (params[i].typed && !params[i].typed->type_name.empty())
|
||||
snippet << params[i].name << ": " << params[i].typed->type_name;
|
||||
else
|
||||
snippet << params[i].name;
|
||||
snippet << "}";
|
||||
}
|
||||
}
|
||||
|
||||
std::string Resolve::GenerateCodeExample(const std::string& name, protocol::CompletionItemKind kind)
|
||||
{
|
||||
std::stringstream example;
|
||||
snippet << ")$0"; // $0 是最终光标位置
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case protocol::CompletionItemKind::kFunction:
|
||||
case protocol::CompletionItemKind::kMethod:
|
||||
example << "// Call " << name << "\n";
|
||||
example << "result := " << name << "(param1, param2);";
|
||||
break;
|
||||
|
||||
case protocol::CompletionItemKind::kClass:
|
||||
example << "// Create instance of " << name << "\n";
|
||||
example << "var obj: " << name << ";\n";
|
||||
example << "obj := " << name << ".Create();";
|
||||
break;
|
||||
|
||||
default:
|
||||
// 不生成示例
|
||||
break;
|
||||
}
|
||||
|
||||
return example.str();
|
||||
}
|
||||
|
||||
std::string Resolve::GetKeywordDocumentation(const std::string& keyword)
|
||||
{
|
||||
std::string lower_keyword = keyword;
|
||||
std::transform(lower_keyword.begin(), lower_keyword.end(), lower_keyword.begin(), ::tolower);
|
||||
|
||||
auto it = kKeywordDocs.find(lower_keyword);
|
||||
if (it != kKeywordDocs.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return "TSF language keyword";
|
||||
}
|
||||
|
||||
std::optional<protocol::DocumentSymbol> Resolve::FindSymbolDetails(const std::string& name, ExecutionContext& context)
|
||||
{
|
||||
// 从符号服务查找详细信息
|
||||
auto& symbol_service = context.GetService<service::Symbol>();
|
||||
auto& document_service = context.GetService<service::Document>();
|
||||
|
||||
// 遍历所有文档查找符号
|
||||
auto uris = document_service.GetAllDocumentUris();
|
||||
for (const auto& uri : uris)
|
||||
{
|
||||
auto symbols = symbol_service.GetDocumentSymbols(uri);
|
||||
|
||||
// 递归查找匹配的符号
|
||||
std::function<std::optional<protocol::DocumentSymbol>(const std::vector<protocol::DocumentSymbol>&)>
|
||||
find_symbol = [&](const std::vector<protocol::DocumentSymbol>& symbol_list)
|
||||
-> std::optional<protocol::DocumentSymbol> {
|
||||
for (const auto& symbol : symbol_list)
|
||||
{
|
||||
if (symbol.name == name)
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// 递归查找子符号
|
||||
auto result = find_symbol(symbol.children.value());
|
||||
if (result.has_value())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
auto result = find_symbol(symbols);
|
||||
if (result.has_value())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
return snippet.str();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
#include "../../service/detail/symbol/symbol_types.hpp"
|
||||
|
||||
namespace lsp::providers::completion_item
|
||||
namespace lsp::provider::completion_item
|
||||
{
|
||||
class Resolve : public IRequestProvider
|
||||
{
|
||||
|
|
@ -14,89 +15,9 @@ namespace lsp::providers::completion_item
|
|||
std::string ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) override;
|
||||
|
||||
private:
|
||||
// 解析补全项,添加详细信息
|
||||
protocol::CompletionItem ResolveCompletionItem(const protocol::CompletionItem& item, ExecutionContext& context);
|
||||
|
||||
// 根据补全项类型获取文档
|
||||
std::string GetDocumentationForItem(const protocol::CompletionItem& item, ExecutionContext& context);
|
||||
|
||||
// 获取函数/方法的详细签名
|
||||
std::string GetDetailedSignature(const std::string& name, protocol::CompletionItemKind kind, ExecutionContext& context);
|
||||
|
||||
// 生成代码示例
|
||||
std::string GenerateCodeExample(const std::string& name, protocol::CompletionItemKind kind);
|
||||
|
||||
// 获取TSF关键字的详细说明
|
||||
std::string GetKeywordDocumentation(const std::string& keyword);
|
||||
|
||||
// 查找符号的详细信息
|
||||
std::optional<protocol::DocumentSymbol> FindSymbolDetails(const std::string& name, ExecutionContext& context);
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// TSF关键字文档
|
||||
const std::unordered_map<std::string, std::string> kKeywordDocs = {
|
||||
{ "function", "Declares a function.\n\nSyntax:\n```tsf\nfunction name(params): return_type;\n```" },
|
||||
{ "procedure", "Declares a procedure (function with no return value).\n\nSyntax:\n```tsf\nprocedure name(params);\n```" },
|
||||
{ "begin", "Starts a block statement.\n\nUsed with: end" },
|
||||
{ "end", "Ends a block statement, case statement, or unit.\n\nUsed with: begin, case, unit" },
|
||||
{ "if", "Conditional statement.\n\nSyntax:\n```tsf\nif condition then\n statement\nelse\n statement\n```" },
|
||||
{ "then", "Part of if-then statement.\n\nFollows the condition in an if statement." },
|
||||
{ "else", "Alternative branch in conditional statement.\n\nUsed with: if-then" },
|
||||
{ "for", "Loop statement.\n\nSyntax:\n```tsf\nfor i := start to end do\n statement\n```" },
|
||||
{ "while", "While loop.\n\nSyntax:\n```tsf\nwhile condition do\n statement\n```" },
|
||||
{ "repeat", "Repeat-until loop.\n\nSyntax:\n```tsf\nrepeat\n statements\nuntil condition;\n```" },
|
||||
{ "until", "Loop termination condition.\n\nUsed with: repeat" },
|
||||
{ "do", "Loop body indicator.\n\nUsed with: for, while" },
|
||||
{ "case", "Case statement for multiple conditions.\n\nSyntax:\n```tsf\ncase expression of\n value1: statement;\n value2: statement;\nelse\n statement;\nend;\n```" },
|
||||
{ "of", "Part of case statement.\n\nUsed with: case, array, set" },
|
||||
{ "var", "Variable declaration.\n\nSyntax:\n```tsf\nvar name: type;\n```" },
|
||||
{ "const", "Constant declaration.\n\nSyntax:\n```tsf\nconst name = value;\n```" },
|
||||
{ "type", "Type declaration.\n\nSyntax:\n```tsf\ntype name = type_definition;\n```" },
|
||||
{ "class", "Class declaration.\n\nSyntax:\n```tsf\ntype MyClass = class\n // members\nend;\n```" },
|
||||
{ "unit", "Unit (module) declaration.\n\nSyntax:\n```tsf\nunit UnitName;\ninterface\n // public declarations\nimplementation\n // private implementation\nend.\n```" },
|
||||
{ "interface", "Public section of a unit.\n\nContains declarations visible to other units." },
|
||||
{ "implementation", "Private section of a unit.\n\nContains implementation details." },
|
||||
{ "uses", "Import other units.\n\nSyntax:\n```tsf\nuses Unit1, Unit2, Unit3;\n```" },
|
||||
{ "public", "Public access modifier.\n\nMembers are accessible from outside the class." },
|
||||
{ "private", "Private access modifier.\n\nMembers are only accessible within the class." },
|
||||
{ "protected", "Protected access modifier.\n\nMembers are accessible within the class and derived classes." },
|
||||
{ "virtual", "Virtual method modifier.\n\nMethod can be overridden in derived classes." },
|
||||
{ "override", "Override method modifier.\n\nMethod overrides a virtual method from base class." },
|
||||
{ "inherited", "Call inherited method.\n\nSyntax:\n```tsf\ninherited MethodName(params);\n```" },
|
||||
{ "property", "Property declaration.\n\nSyntax:\n```tsf\nproperty Name: Type read GetMethod write SetMethod;\n```" },
|
||||
{ "true", "Boolean literal.\n\nRepresents logical true value." },
|
||||
{ "false", "Boolean literal.\n\nRepresents logical false value." },
|
||||
{ "nil", "Null pointer value.\n\nRepresents an uninitialized or empty reference." },
|
||||
{ "self", "Reference to current object instance.\n\nUsed within class methods." },
|
||||
{ "and", "Logical AND operator.\n\nReturns true if both operands are true." },
|
||||
{ "or", "Logical OR operator.\n\nReturns true if at least one operand is true." },
|
||||
{ "not", "Logical NOT operator.\n\nInverts the boolean value." },
|
||||
{ "div", "Integer division operator.\n\nReturns integer quotient." },
|
||||
{ "mod", "Modulo operator.\n\nReturns remainder of division." },
|
||||
{ "shl", "Shift left operator.\n\nShifts bits to the left." },
|
||||
{ "shr", "Shift right operator.\n\nShifts bits to the right." },
|
||||
{ "break", "Exit from loop.\n\nImmediately exits the current loop." },
|
||||
{ "continue", "Continue to next iteration.\n\nSkips remaining statements in current loop iteration." },
|
||||
{ "exit", "Exit from procedure/function.\n\nImmediately returns from current procedure." },
|
||||
{ "return", "Return value from function.\n\nSyntax:\n```tsf\nreturn expression;\n```" },
|
||||
{ "try", "Exception handling block.\n\nSyntax:\n```tsf\ntry\n statements\nexcept\n exception_handler\nend;\n```" },
|
||||
{ "except", "Exception handler.\n\nUsed with: try" },
|
||||
{ "finally", "Finally block.\n\nAlways executed after try block." },
|
||||
{ "raise", "Raise an exception.\n\nSyntax:\n```tsf\nraise Exception.Create('message');\n```" }
|
||||
};
|
||||
|
||||
// 内置函数文档
|
||||
const std::unordered_map<std::string, std::string> kBuiltinFunctions = {
|
||||
{ "writeln", "**writeln**(text: string)\n\nWrites text to standard output with newline.\n\nExample:\n```tsf\nwriteln('Hello, World!');\n```" },
|
||||
{ "write", "**write**(text: string)\n\nWrites text to standard output without newline.\n\nExample:\n```tsf\nwrite('Enter name: ');\n```" },
|
||||
{ "readln", "**readln**(): string\n\nReads a line from standard input.\n\nExample:\n```tsf\nvar name: string;\nname := readln();\n```" },
|
||||
{ "length", "**length**(s: string): integer\n\nReturns the length of a string.\n\nExample:\n```tsf\nlen := length('hello'); // returns 5\n```" },
|
||||
{ "copy", "**copy**(s: string; index, count: integer): string\n\nReturns a substring.\n\nExample:\n```tsf\nsubstr := copy('hello', 2, 3); // returns 'ell'\n```" },
|
||||
{ "pos", "**pos**(substr, s: string): integer\n\nFinds position of substring.\n\nExample:\n```tsf\nindex := pos('lo', 'hello'); // returns 4\n```" },
|
||||
{ "delete", "**delete**(var s: string; index, count: integer)\n\nDeletes characters from string.\n\nExample:\n```tsf\ndelete(s, 1, 3); // removes first 3 characters\n```" },
|
||||
{ "insert", "**insert**(source: string; var target: string; index: integer)\n\nInserts string at position.\n\nExample:\n```tsf\ninsert('abc', s, 5);\n```" }
|
||||
static protocol::string GeneratorFunctionMarkdown(const service::SymbolInfo& symbol_info);
|
||||
static protocol::string GenerateFunctionSnippet(const service::SymbolInfo& symbol_info);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./resolve.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::document_link
|
||||
namespace lsp::provider::document_link
|
||||
{
|
||||
std::string Resolve::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::document_link
|
||||
namespace lsp::provider::document_link
|
||||
{
|
||||
class Resolve : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include "./exit.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
std::string Exit::GetMethod() const
|
||||
{
|
||||
return "exit";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
class Exit : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./initialize.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
std::string Initialize::GetMethod() const
|
||||
{
|
||||
|
|
@ -35,53 +35,69 @@ namespace lsp::providers
|
|||
{
|
||||
protocol::InitializeResult result;
|
||||
result.serverInfo.name = "TSL Language Server";
|
||||
result.serverInfo.version = "1.0.0";
|
||||
protocol::TextDocumentSyncOptions text_document_sync_options;
|
||||
text_document_sync_options.openClose = true;
|
||||
text_document_sync_options.change = protocol::TextDocumentSyncKind::kIncremental;
|
||||
protocol::CompletionOptions completion_provider;
|
||||
completion_provider.resolveProvider = false;
|
||||
protocol::SemanticTokensOptions semantic_tokens_options;
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Namespace);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Type);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Class);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Enum);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Interface);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Struct);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::TypeParameter);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Parameter);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Variable);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Property);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::EnumMember);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Event);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Function);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Method);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Macro);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Keyword);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Modifier);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Comment);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::String);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Number);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Regexp);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Operator);
|
||||
semantic_tokens_options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Decorator);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Declaration);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Definition);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Readonly);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Static);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Deprecated);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Abstract);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Async);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Modification);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Documentation);
|
||||
semantic_tokens_options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::DefaultLibrary);
|
||||
semantic_tokens_options.range = true;
|
||||
semantic_tokens_options.full = protocol::SemanticTokensOptions::Full{.delta = true};
|
||||
|
||||
result.capabilities.textDocumentSync = text_document_sync_options;
|
||||
result.capabilities.completionProvider = completion_provider;
|
||||
result.capabilities.semanticTokensProvider = semantic_tokens_options;
|
||||
result.serverInfo.version = __DATE__;
|
||||
result.capabilities.textDocumentSync = BuildTextDocumentSyncOptions();
|
||||
result.capabilities.completionProvider = BuildCompletionOptions();
|
||||
// result.capabilities.semanticTokensProvider = BuildSemanticTokenOptions();
|
||||
return result;
|
||||
}
|
||||
|
||||
protocol::TextDocumentSyncOptions Initialize::BuildTextDocumentSyncOptions()
|
||||
{
|
||||
protocol::TextDocumentSyncOptions options;
|
||||
options.openClose = true;
|
||||
options.change = protocol::TextDocumentSyncKind::kIncremental;
|
||||
return options;
|
||||
}
|
||||
|
||||
protocol::CompletionOptions Initialize::BuildCompletionOptions()
|
||||
{
|
||||
protocol::CompletionOptions options;
|
||||
options.triggerCharacters = { std::vector<std::string>{ "." } };
|
||||
options.resolveProvider = true;
|
||||
options.completionItem = {.labelDetailsSupport = true};
|
||||
return options;
|
||||
}
|
||||
|
||||
protocol::SemanticTokensOptions Initialize::BuildSemanticTokenOptions()
|
||||
{
|
||||
protocol::SemanticTokensOptions options;
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Namespace);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Type);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Class);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Enum);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Interface);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Struct);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::TypeParameter);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Parameter);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Variable);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Property);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::EnumMember);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Event);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Function);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Method);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Macro);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Keyword);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Modifier);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Comment);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::String);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Number);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Regexp);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Operator);
|
||||
options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Decorator);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Declaration);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Definition);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Readonly);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Static);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Deprecated);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Abstract);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Async);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Modification);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Documentation);
|
||||
options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::DefaultLibrary);
|
||||
options.range = true;
|
||||
options.full = protocol::SemanticTokensOptions::Full{ .delta = true };
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
class Initialize : public IRequestProvider
|
||||
{
|
||||
|
|
@ -14,5 +14,8 @@ namespace lsp::providers
|
|||
|
||||
private:
|
||||
protocol::InitializeResult BuildInitializeResult();
|
||||
protocol::TextDocumentSyncOptions BuildTextDocumentSyncOptions();
|
||||
protocol::CompletionOptions BuildCompletionOptions();
|
||||
protocol::SemanticTokensOptions BuildSemanticTokenOptions();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include "./initialized.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
std::string Initialized::GetMethod() const
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
class Initialized : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./resolve.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::inlay_hint
|
||||
namespace lsp::provider::inlay_hint
|
||||
{
|
||||
std::string Resolve::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::inlay_hint
|
||||
namespace lsp::provider::inlay_hint
|
||||
{
|
||||
class Resolve : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./shutdown.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
std::string Shutdown::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
namespace lsp::provider
|
||||
{
|
||||
class Shutdown : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./event.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::telemetry
|
||||
namespace lsp::provider::telemetry
|
||||
{
|
||||
std::string Event::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::telemetry
|
||||
namespace lsp::provider::telemetry
|
||||
{
|
||||
class Event : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./code_action.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string CodeAction::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class CodeAction : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./code_lens.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string CodeLens::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class CodeLens : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./color_presentation.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string ColorPresentation::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class ColorPresentation : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include "./completion.hpp"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include "../../language/keyword_manager.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
#include "../../service/symbol.hpp"
|
||||
#include "../../utils/string.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "./completion.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Completion::GetMethod() const
|
||||
{
|
||||
|
|
@ -18,270 +22,456 @@ namespace lsp::providers::text_document
|
|||
|
||||
std::string Completion::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
|
||||
{
|
||||
spdlog::debug("TextDocumentCompletionProvider: Providing response for method {}", request.method);
|
||||
spdlog::debug("{}: Processing completion request", GetProviderName());
|
||||
|
||||
// 验证请求是否包含参数
|
||||
if (!request.params.has_value())
|
||||
{
|
||||
spdlog::warn("{}: Missing params in request", GetProviderName());
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInvalidParams, "Missing params");
|
||||
}
|
||||
|
||||
// 从 variant 中提取参数
|
||||
protocol::CompletionParams completion_params = transform::As<protocol::CompletionParams>(request.params.value());
|
||||
protocol::CompletionList completion_list = BuildCompletionResponse(completion_params, context);
|
||||
|
||||
// 构建响应消息
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.result = transform::LSPAny(completion_list);
|
||||
|
||||
std::optional<std::string> json = transform::Serialize(response);
|
||||
if (!json.has_value())
|
||||
{
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, "Failed to serialize response");
|
||||
}
|
||||
|
||||
return json.value();
|
||||
}
|
||||
|
||||
// ================== Core Completion Logic ==================
|
||||
protocol::CompletionList Completion::BuildCompletionResponse(const protocol::CompletionParams& params, ExecutionContext& context)
|
||||
{
|
||||
spdlog::trace("{}: Processing completion request for URI='{}', Position=({}, {})", GetProviderName(), params.textDocument.uri, params.position.line, params.position.character);
|
||||
spdlog::trace("{}: URI='{}', Position=({}, {})", GetProviderName(), params.textDocument.uri, params.position.line, params.position.character);
|
||||
|
||||
// 获取补全前缀
|
||||
std::string prefix = ExtractPrefix(params.textDocument.uri, params.position, context);
|
||||
std::string completion_context = GetCompletionContext(params.textDocument.uri, params.position, context);
|
||||
spdlog::debug("{}: Prefix='{}', Context='{}'", GetProviderName(), prefix, completion_context);
|
||||
CompletionContext comp_context = ExtractCompletionContext(params, context);
|
||||
|
||||
// 如果提供了 context,可以使用其中的信息
|
||||
if (params.context.has_value())
|
||||
{
|
||||
spdlog::trace("{}: Trigger kind: {}", GetProviderName(), static_cast<int>(params.context->triggerKind));
|
||||
if (params.context->triggerCharacter.has_value())
|
||||
spdlog::trace("{}: Trigger character: '{}'", GetProviderName(), params.context->triggerCharacter.value());
|
||||
}
|
||||
// Log completion context details
|
||||
spdlog::debug("{}: Completion context - prefix='{}', is_member_access={}, is_constructor={}, object_name='{}'",
|
||||
GetProviderName(),
|
||||
comp_context.prefix,
|
||||
comp_context.is_member_access,
|
||||
comp_context.is_constructor_context,
|
||||
comp_context.object_name);
|
||||
|
||||
// 收集所有补全项
|
||||
std::vector<protocol::CompletionItem> all_items;
|
||||
if (!IsMemberCompletion(completion_context))
|
||||
{
|
||||
std::string object_name = ExtractObjectName(completion_context);
|
||||
if (!object_name.empty())
|
||||
{
|
||||
auto member_item = ProvideMemberCompletions(params.textDocument.uri, params.position, object_name, context);
|
||||
all_items.insert(all_items.end(), member_item.begin(), member_item.end());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto keyword_items = ProvideKeywordCompletions(prefix);
|
||||
all_items.insert(all_items.end(), keyword_items.begin(), keyword_items.end());
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
|
||||
auto symbol_items = ProvideSymbolCompletions(params.textDocument.uri, prefix, context);
|
||||
all_items.insert(all_items.end(), symbol_items.begin(), symbol_items.end());
|
||||
auto keyword_items = ProvideKeywordCompletions(comp_context.prefix);
|
||||
spdlog::trace("{}: Found {} keyword completions", GetProviderName(), keyword_items.size());
|
||||
AppendCompletions(items, keyword_items);
|
||||
|
||||
auto snippet_items = ProvideSnippetCompletions(completion_context);
|
||||
all_items.insert(all_items.end(), snippet_items.begin(), snippet_items.end());
|
||||
}
|
||||
auto function_items = ProvideFunctionCompletions(comp_context, context);
|
||||
spdlog::trace("{}: Found {} global function completions", GetProviderName(), function_items.size());
|
||||
AppendCompletions(items, function_items);
|
||||
|
||||
size_t before_filter = items.size();
|
||||
items = FilterAndSortCompletions(items, comp_context.prefix);
|
||||
spdlog::debug("{}: Completions before filter: {}, after filter: {}", GetProviderName(), before_filter, items.size());
|
||||
|
||||
// 构建补全列表
|
||||
protocol::CompletionList result;
|
||||
result.isIncomplete = false; // 表示这是完整的补全列表
|
||||
result.items = std::move(all_items);
|
||||
|
||||
spdlog::info("{}: Provided {} completion items", GetProviderName(), result.items.size());
|
||||
result.isIncomplete = false;
|
||||
result.items = std::move(items);
|
||||
spdlog::info("{}: Provided {} completion items for prefix '{}'", GetProviderName(), result.items.size(), comp_context.prefix);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Completion::ExtractPrefix(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context)
|
||||
std::vector<protocol::CompletionItem> Completion::ProvideFunctionCompletions(const CompletionContext& context, ExecutionContext& exec_context)
|
||||
{
|
||||
auto& document_service = context.GetService<service::Document>();
|
||||
auto content = document_service.GetContent(uri);
|
||||
if (!content.has_value())
|
||||
return "";
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
auto& symbol_service = exec_context.GetService<service::Symbol>();
|
||||
auto global_symbols = symbol_service.GetGlobalFunctions();
|
||||
for (const auto& symbol : global_symbols)
|
||||
{
|
||||
for (const auto& symbol_info : symbol.symbols)
|
||||
{
|
||||
if (symbol_info.kind == service::TsfSymbolKind::kFunction)
|
||||
{
|
||||
if (context.prefix.empty() || utils::StartsWith(symbol_info.name, context.prefix, true))
|
||||
{
|
||||
protocol::CompletionItem item;
|
||||
item.label = symbol_info.name;
|
||||
item.kind = protocol::CompletionItemKind::kFunction;
|
||||
item.labelDetails = protocol::CompletionItemLabelDetails{
|
||||
.detail = BuildFunctionSignature(symbol_info),
|
||||
.description = "[G]"
|
||||
};
|
||||
// item.insertTextFormat = protocol::InsertTextFormat::kSnippet;
|
||||
item.additionalTextEdits = {};
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto symbols = symbol_service.GetDocumentSymbols(context.uri);
|
||||
for (const auto& symbol : symbols)
|
||||
{
|
||||
if (symbol.kind == service::TsfSymbolKind::kFunction)
|
||||
{
|
||||
if (context.prefix.empty() || utils::StartsWith(symbol.name, context.prefix, true))
|
||||
{
|
||||
protocol::CompletionItem item;
|
||||
item.label = symbol.name;
|
||||
item.kind = protocol::CompletionItemKind::kFunction;
|
||||
item.insertText = symbol.name + "($0)";
|
||||
item.insertTextFormat = protocol::InsertTextFormat::kSnippet;
|
||||
item.additionalTextEdits = {};
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
Completion::CompletionContext Completion::ExtractCompletionContext(const protocol::CompletionParams& params, ExecutionContext& context)
|
||||
{
|
||||
CompletionContext result;
|
||||
result.uri = params.textDocument.uri;
|
||||
result.position = params.position;
|
||||
|
||||
auto& document_service = context.GetService<service::Document>();
|
||||
auto content = document_service.GetContent(result.uri);
|
||||
if (!content.has_value())
|
||||
{
|
||||
spdlog::warn("{}: Document content not available for URI: {}", GetProviderName(), result.uri);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Extract line content up to cursor
|
||||
size_t line_start = 0;
|
||||
size_t current_line = 0;
|
||||
|
||||
for (size_t i = 0; i < content->length(); i++)
|
||||
{
|
||||
if (current_line == position.line)
|
||||
if (current_line == result.position.line)
|
||||
{
|
||||
line_start = i;
|
||||
break;
|
||||
}
|
||||
if ((*content)[i] == '\n')
|
||||
{
|
||||
current_line++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t cursor_pos = line_start + position.character;
|
||||
size_t cursor_pos = line_start + result.position.character;
|
||||
if (cursor_pos > content->length())
|
||||
cursor_pos = content->length();
|
||||
|
||||
// Extract line content up to cursor
|
||||
result.line_context = content->substr(line_start, cursor_pos - line_start);
|
||||
|
||||
// Check for constructor contexts
|
||||
result.is_constructor_context = DetectConstructorContext(result.line_context);
|
||||
|
||||
// Check for member access patterns
|
||||
result.is_member_access = DetectMemberAccess(result.line_context);
|
||||
|
||||
if (result.is_member_access)
|
||||
{
|
||||
result.object_name = ExtractObjectName(result.line_context);
|
||||
result.prefix = ExtractMemberPrefix(result.line_context);
|
||||
spdlog::trace("{}: Member access detected - object='{}', prefix='{}'", GetProviderName(), result.object_name, result.prefix);
|
||||
}
|
||||
else if (result.is_constructor_context)
|
||||
{
|
||||
// Special handling for constructor context prefix extraction
|
||||
result.prefix = ExtractConstructorPrefix(result.line_context);
|
||||
spdlog::trace("{}: Constructor context detected - prefix='{}'", GetProviderName(), result.prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.prefix = ExtractPrefix(cursor_pos, line_start, *content);
|
||||
spdlog::trace("{}: Normal context - prefix='{}'", GetProviderName(), result.prefix);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Completion::DetectConstructorContext(const std::string& line)
|
||||
{
|
||||
std::string line_lower = utils::ToLower(line);
|
||||
|
||||
// Check for "new " pattern (case-insensitive)
|
||||
size_t new_pos = line_lower.rfind("new ");
|
||||
if (new_pos != std::string::npos)
|
||||
{
|
||||
// Make sure we're after "new " keyword
|
||||
std::string after_new = line.substr(new_pos + 4);
|
||||
after_new = utils::Trim(after_new);
|
||||
// If there's no content after "new " or incomplete class name (no parenthesis yet)
|
||||
if (after_new.empty() || after_new.find("(") == std::string::npos)
|
||||
{
|
||||
spdlog::trace("{}: 'new' constructor context detected", GetProviderName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for createobject(" pattern (case-insensitive)
|
||||
size_t create_pos = line_lower.rfind("createobject(\"");
|
||||
if (create_pos != std::string::npos)
|
||||
{
|
||||
// Check if we're inside the string literal
|
||||
size_t quote_start = create_pos + 14; // length of "createobject(\""
|
||||
size_t quote_end = line.find('"', quote_start);
|
||||
if (quote_end == std::string::npos || quote_end > line.length())
|
||||
{
|
||||
spdlog::trace("{}: 'createobject(\"' constructor context detected", GetProviderName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for createobject(' pattern (single quote variant, case-insensitive)
|
||||
create_pos = line_lower.rfind("createobject('");
|
||||
if (create_pos != std::string::npos)
|
||||
{
|
||||
size_t quote_start = create_pos + 14;
|
||||
size_t quote_end = line.find('\'', quote_start);
|
||||
if (quote_end == std::string::npos || quote_end > line.length())
|
||||
{
|
||||
spdlog::trace("{}: 'createobject('' constructor context detected", GetProviderName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Completion::ExtractConstructorPrefix(const std::string& line)
|
||||
{
|
||||
std::string line_lower = utils::ToLower(line);
|
||||
|
||||
// Handle createobject("xxx or createobject('xxx
|
||||
size_t create_pos = line_lower.rfind("createobject(\"");
|
||||
if (create_pos != std::string::npos)
|
||||
{
|
||||
std::string prefix = line.substr(create_pos + 14); // 14 = length of "createobject(\""
|
||||
spdlog::trace("{}: Extracted constructor prefix from createobject(\"): '{}'", GetProviderName(), prefix);
|
||||
return prefix;
|
||||
}
|
||||
|
||||
create_pos = line_lower.rfind("createobject('");
|
||||
if (create_pos != std::string::npos)
|
||||
{
|
||||
std::string prefix = line.substr(create_pos + 14);
|
||||
spdlog::trace("{}: Extracted constructor prefix from createobject('): '{}'", GetProviderName(), prefix);
|
||||
return prefix;
|
||||
}
|
||||
|
||||
// Handle new xxx
|
||||
size_t new_pos = line_lower.rfind("new ");
|
||||
if (new_pos != std::string::npos)
|
||||
{
|
||||
std::string after_new = line.substr(new_pos + 4);
|
||||
std::string prefix = utils::Trim(after_new);
|
||||
spdlog::trace("{}: Extracted constructor prefix from 'new': '{}'", GetProviderName(), prefix);
|
||||
return prefix;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Completion::ExtractPrefix(size_t cursor_pos, size_t line_start, const std::string& content)
|
||||
{
|
||||
size_t prefix_start = cursor_pos;
|
||||
while (prefix_start > line_start)
|
||||
{
|
||||
char ch = (*content)[prefix_start - 1];
|
||||
char ch = content[prefix_start - 1];
|
||||
if (!std::isalnum(ch) && ch != '_')
|
||||
break;
|
||||
prefix_start--;
|
||||
}
|
||||
|
||||
return content->substr(prefix_start, cursor_pos - prefix_start);
|
||||
return content.substr(prefix_start, cursor_pos - prefix_start);
|
||||
}
|
||||
|
||||
std::string Completion::GetCompletionContext(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context)
|
||||
std::string Completion::ExtractMemberPrefix(const std::string& line)
|
||||
{
|
||||
auto& document_service = context.GetService<service::Document>();
|
||||
size_t last_dot = line.find_last_of('.');
|
||||
if (last_dot == std::string::npos || last_dot == line.length() - 1)
|
||||
return "";
|
||||
return line.substr(last_dot + 1);
|
||||
}
|
||||
|
||||
auto content = document_service.GetContent(uri);
|
||||
if (!content.has_value())
|
||||
bool Completion::DetectMemberAccess(const std::string& line)
|
||||
{
|
||||
// Check for patterns: obj., class(name)., unit(name).
|
||||
if (line.find('.') == std::string::npos)
|
||||
return false;
|
||||
|
||||
std::string line_lower = utils::ToLower(line);
|
||||
|
||||
// Check for class() or unit() patterns (case-insensitive)
|
||||
if (line_lower.find("class(") != std::string::npos || line_lower.find("unit(") != std::string::npos)
|
||||
return true;
|
||||
|
||||
// Check for simple object.member pattern
|
||||
size_t last_dot = line.find_last_of('.');
|
||||
if (last_dot != std::string::npos && last_dot > 0)
|
||||
{
|
||||
// Make sure there's an identifier before the dot
|
||||
char before_dot = line[last_dot - 1];
|
||||
return std::isalnum(before_dot) || before_dot == '_' || before_dot == ')';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Completion::ExtractObjectName(const std::string& line)
|
||||
{
|
||||
size_t last_dot = line.find_last_of('.');
|
||||
if (last_dot == std::string::npos)
|
||||
return "";
|
||||
|
||||
size_t line_start = 0;
|
||||
size_t line_end = content->length();
|
||||
size_t current_line = 0;
|
||||
std::string before_dot = line.substr(0, last_dot);
|
||||
std::string before_dot_lower = utils::ToLower(before_dot);
|
||||
|
||||
for (size_t i = 0; i < content->length(); i++)
|
||||
// Check for class(...) or unit(...) patterns (case-insensitive)
|
||||
if (before_dot_lower.find("class(") != std::string::npos)
|
||||
{
|
||||
if (current_line == position.line)
|
||||
size_t start = before_dot_lower.find("class(");
|
||||
return before_dot.substr(start);
|
||||
}
|
||||
else if (before_dot_lower.find("unit(") != std::string::npos)
|
||||
{
|
||||
line_start = i;
|
||||
for (size_t j = i; j < content->length(); j++)
|
||||
size_t start = before_dot_lower.find("unit(");
|
||||
return before_dot.substr(start);
|
||||
}
|
||||
|
||||
// Extract simple identifier
|
||||
size_t start = last_dot;
|
||||
while (start > 0)
|
||||
{
|
||||
if ((*content)[j] == '\n')
|
||||
{
|
||||
line_end = j;
|
||||
char ch = line[start - 1];
|
||||
if (!std::isalnum(ch) && ch != '_')
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((*content)[i] == '\n')
|
||||
{
|
||||
current_line++;
|
||||
}
|
||||
start--;
|
||||
}
|
||||
|
||||
size_t cursor_pos = line_start + position.character;
|
||||
if (cursor_pos > line_end)
|
||||
cursor_pos = line_end;
|
||||
|
||||
return content->substr(line_start, cursor_pos - line_start);
|
||||
}
|
||||
|
||||
std::vector<protocol::CompletionItem> Completion::ProvideSymbolCompletions(const protocol::DocumentUri& uri, const std::string& prefix, ExecutionContext& context)
|
||||
{
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
|
||||
// 从容器获取符号服务
|
||||
auto& symbol_service = context.GetService<service::Symbol>();
|
||||
|
||||
auto symbols = symbol_service.GetDocumentSymbols(uri);
|
||||
|
||||
std::function<void(const std::vector<protocol::DocumentSymbol>&)> process_symbols =
|
||||
[&](const std::vector<protocol::DocumentSymbol>& symbol_list) {
|
||||
for (const auto& symbol : symbol_list)
|
||||
{
|
||||
if (!prefix.empty() && symbol.name.find(prefix) != 0)
|
||||
{
|
||||
process_symbols(symbol.children.value());
|
||||
continue;
|
||||
}
|
||||
|
||||
protocol::CompletionItem item = SymbolToCompletionItem(symbol);
|
||||
items.push_back(item);
|
||||
|
||||
process_symbols(symbol.children.value());
|
||||
}
|
||||
};
|
||||
|
||||
process_symbols(symbols);
|
||||
|
||||
spdlog::debug("{}: Found {} symbol completions", GetProviderName(), items.size());
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<protocol::CompletionItem> Completion::ProvideMemberCompletions(const protocol::DocumentUri& uri, const protocol::Position& position, const std::string& object_name, ExecutionContext& context)
|
||||
{
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
|
||||
// TODO: 实现成员补全
|
||||
spdlog::debug("{}: Member completion for '{}' not fully implemented", GetProviderName(), object_name);
|
||||
|
||||
if (!object_name.empty())
|
||||
{
|
||||
protocol::CompletionItem item;
|
||||
item.label = "Create";
|
||||
item.kind = protocol::CompletionItemKind::kMethod;
|
||||
item.detail = "Constructor method";
|
||||
item.insertText = "Create()";
|
||||
items.push_back(item);
|
||||
|
||||
item.label = "Free";
|
||||
item.kind = protocol::CompletionItemKind::kMethod;
|
||||
item.detail = "Destructor method";
|
||||
item.insertText = "Free";
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
return line.substr(start, last_dot - start);
|
||||
}
|
||||
|
||||
// ================== Keyword Completions ==================
|
||||
std::vector<protocol::CompletionItem> Completion::ProvideKeywordCompletions(const std::string& prefix)
|
||||
{
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
|
||||
// 从 tsl_keywords_ 获取补全项
|
||||
auto tslItems = tsl_keywords_.GetCompletionItems(prefix);
|
||||
|
||||
for (const auto& tslItem : tslItems)
|
||||
auto keywords_item = tsl::KeywordManager::GetInstance().GetKeyWordByPrefix(utils::ToLower(prefix));
|
||||
for (const auto& keyword : keywords_item)
|
||||
{
|
||||
protocol::CompletionItem item;
|
||||
item.label = tslItem.label;
|
||||
item.label = keyword.keyword;
|
||||
item.kind = protocol::CompletionItemKind::kKeyword;
|
||||
item.detail = "TSL Keyword";
|
||||
|
||||
// 创建文档内容
|
||||
protocol::MarkupContent documentation;
|
||||
documentation.kind = protocol::MarkupKindLiterals::PlainText;
|
||||
documentation.value = "TSL language keyword";
|
||||
item.documentation = documentation;
|
||||
|
||||
item.insertText = tslItem.label;
|
||||
|
||||
item.labelDetails = protocol::CompletionItemLabelDetails{
|
||||
.detail = "",
|
||||
.description = "keyword"
|
||||
};
|
||||
item.insertText = keyword.keyword;
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
spdlog::debug("{}: Found {} keyword completions", GetProviderName(), items.size());
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<protocol::CompletionItem> Completion::ProvideContextualCompletions(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position, const std::string& prefix)
|
||||
void Completion::AppendCompletions(std::vector<protocol::CompletionItem>& target, const std::vector<protocol::CompletionItem>& source)
|
||||
{
|
||||
spdlog::debug("{}: Processing contextual completions for URI: {}", GetProviderName(), textDocument.uri);
|
||||
target.insert(target.end(), source.begin(), source.end());
|
||||
}
|
||||
|
||||
std::vector<protocol::CompletionItem> items;
|
||||
|
||||
// TODO: 基于上下文提供补全
|
||||
// 示例:添加一个变量补全
|
||||
if (!prefix.empty() && prefix[0] == '$')
|
||||
std::vector<protocol::CompletionItem> Completion::FilterAndSortCompletions(const std::vector<protocol::CompletionItem>& items, const std::string& prefix)
|
||||
{
|
||||
protocol::CompletionItem varItem;
|
||||
varItem.label = "$myVariable";
|
||||
varItem.kind = protocol::CompletionItemKind::kVariable;
|
||||
varItem.detail = "Local variable";
|
||||
varItem.insertText = "$myVariable";
|
||||
std::vector<protocol::CompletionItem> filtered;
|
||||
std::set<std::string> seen;
|
||||
|
||||
protocol::MarkupContent doc;
|
||||
doc.kind = protocol::MarkupKindLiterals::Markdown;
|
||||
doc.value = "Example variable completion";
|
||||
varItem.documentation = doc;
|
||||
for (const auto& item : items)
|
||||
{
|
||||
// Remove duplicates
|
||||
if (seen.find(item.label) != seen.end())
|
||||
continue;
|
||||
seen.insert(item.label);
|
||||
|
||||
items.push_back(varItem);
|
||||
// Filter by prefix if provided (case-insensitive)
|
||||
if (!prefix.empty() && !utils::StartsWith(item.label, prefix, true))
|
||||
continue;
|
||||
|
||||
filtered.push_back(item);
|
||||
}
|
||||
|
||||
spdlog::debug("{}: Found {} contextual completions", GetProviderName(), items.size());
|
||||
return items;
|
||||
std::sort(filtered.begin(), filtered.end(), [&prefix](const protocol::CompletionItem& a, const protocol::CompletionItem& b) -> bool {
|
||||
// Exact matches first (case-insensitive)
|
||||
bool a_exact = utils::ToLower(a.label) == utils::ToLower(prefix);
|
||||
bool b_exact = utils::ToLower(b.label) == utils::ToLower(prefix);
|
||||
if (a_exact != b_exact)
|
||||
return a_exact;
|
||||
|
||||
// Then by kind (function > variable > others > keyword)
|
||||
if (a.kind.has_value() && b.kind.has_value() && a.kind.value() != b.kind.value())
|
||||
{
|
||||
auto kind_priority = [](protocol::CompletionItemKind kind) -> int {
|
||||
switch (kind)
|
||||
{
|
||||
case protocol::CompletionItemKind::kFunction:
|
||||
case protocol::CompletionItemKind::kMethod:
|
||||
return 0; // Highest priority
|
||||
case protocol::CompletionItemKind::kVariable:
|
||||
case protocol::CompletionItemKind::kField:
|
||||
case protocol::CompletionItemKind::kProperty:
|
||||
return 1;
|
||||
case protocol::CompletionItemKind::kClass:
|
||||
return 2;
|
||||
case protocol::CompletionItemKind::kModule:
|
||||
return 3;
|
||||
case protocol::CompletionItemKind::kConstant:
|
||||
return 4;
|
||||
case protocol::CompletionItemKind::kSnippet:
|
||||
return 5;
|
||||
case protocol::CompletionItemKind::kKeyword:
|
||||
return 6; // Lowest priority
|
||||
default:
|
||||
return 5; // Others
|
||||
}
|
||||
};
|
||||
|
||||
int a_priority = kind_priority(a.kind.value());
|
||||
int b_priority = kind_priority(b.kind.value());
|
||||
if (a_priority != b_priority)
|
||||
return a_priority < b_priority;
|
||||
}
|
||||
|
||||
// Finally alphabetically (case-insensitive)
|
||||
std::string a_lower = utils::ToLower(a.label);
|
||||
std::string b_lower = utils::ToLower(b.label);
|
||||
return a_lower < b_lower;
|
||||
});
|
||||
|
||||
spdlog::trace("{}: Filtered {} items to {} items", GetProviderName(), items.size(), filtered.size());
|
||||
return filtered;
|
||||
}
|
||||
|
||||
std::string Completion::BuildFunctionSignature(const service::SymbolInfo& symbol)
|
||||
{
|
||||
if (!symbol.callable)
|
||||
return "";
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
|
||||
const auto& params = symbol.callable->parameters;
|
||||
for (size_t i = 0; i < params.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
ss << (params[i].typed && !params[i].typed->type_name.empty() ? "; " : ", ");
|
||||
const auto& param = params[i];
|
||||
ss << param.name;
|
||||
if (param.typed && !param.typed->type_name.empty())
|
||||
{
|
||||
ss << ": " << param.typed->type_name;
|
||||
}
|
||||
}
|
||||
ss << ")";
|
||||
if (symbol.callable->return_type)
|
||||
ss << " -> " << *symbol.callable->return_type;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../../language/tsl_keywords.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
#include "../../service/detail/symbol/symbol_types.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Completion : public IRequestProvider
|
||||
{
|
||||
|
|
@ -14,25 +14,31 @@ namespace lsp::providers::text_document
|
|||
std::string ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) override;
|
||||
|
||||
private:
|
||||
// 构建完整的补全响应
|
||||
struct CompletionContext
|
||||
{
|
||||
protocol::DocumentUri uri;
|
||||
protocol::Position position;
|
||||
std::string prefix;
|
||||
std::string line_context;
|
||||
std::string object_name;
|
||||
bool is_member_access = false;
|
||||
bool is_constructor_context = false;
|
||||
};
|
||||
|
||||
protocol::CompletionList BuildCompletionResponse(const protocol::CompletionParams& params, ExecutionContext& context);
|
||||
|
||||
// 获取补全前缀(从文档内容和位置计算)
|
||||
std::string ExtractPrefix(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context);
|
||||
|
||||
// 提供不同类型的补全
|
||||
std::vector<protocol::CompletionItem> ProvideContextualCompletions(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position, const std::string& prefix);
|
||||
std::string GetCompletionContext(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context);
|
||||
std::vector<protocol::CompletionItem> ProvideKeywordCompletions(const std::string& prefix);
|
||||
std::vector<protocol::CompletionItem> ProvideSymbolCompletions(const protocol::DocumentUri& uri, const std::string& prefix, ExecutionContext& context);
|
||||
std::vector<protocol::CompletionItem> ProvideMemberCompletions(const protocol::DocumentUri& uri, const protocol::Position& position, const std::string& object_name, ExecutionContext& context);
|
||||
std::vector<protocol::CompletionItem> ProvideSnippetCompletions(const std::string& context);
|
||||
std::vector<protocol::CompletionItem> ProvideFunctionCompletions(const CompletionContext& context, ExecutionContext& exec_context);
|
||||
|
||||
protocol::CompletionItem SymbolToCompletionItem(const protocol::DocumentSymbol& symbol);
|
||||
bool IsMemberCompletion(const std::string& context);
|
||||
std::string ExtractObjectName(const std::string& context);
|
||||
CompletionContext ExtractCompletionContext(const protocol::CompletionParams& params, ExecutionContext& context);
|
||||
std::string ExtractPrefix(size_t cursor_pos, size_t line_start, const std::string& content);
|
||||
std::string ExtractMemberPrefix(const std::string& line);
|
||||
std::string ExtractConstructorPrefix(const std::string& line);
|
||||
std::string ExtractObjectName(const std::string& line);
|
||||
bool DetectConstructorContext(const std::string& line);
|
||||
bool DetectMemberAccess(const std::string& line);
|
||||
void AppendCompletions(std::vector<protocol::CompletionItem>& target, const std::vector<protocol::CompletionItem>& source);
|
||||
std::vector<protocol::CompletionItem> FilterAndSortCompletions(const std::vector<protocol::CompletionItem>& items, const std::string& prefix);
|
||||
|
||||
private:
|
||||
tsl::TslKeywords tsl_keywords_;
|
||||
static std::string BuildFunctionSignature(const service::SymbolInfo& symbol);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Definition::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Definition : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./diagnostic.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Diagnostic::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Diagnostic : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
|
||||
std::string DidChange::GetMethod() const
|
||||
|
|
@ -20,12 +20,12 @@ namespace lsp::providers::text_document
|
|||
{
|
||||
spdlog::debug("TextDocumentDidChangeProvider: Providing response for method {}", notification.method);
|
||||
|
||||
protocol::DidChangeTextDocumentParams did_change_text_document_params = transform::As<protocol::DidChangeTextDocumentParams>(notification.params.value());
|
||||
protocol::DidChangeTextDocumentParams params = transform::As<protocol::DidChangeTextDocumentParams>(notification.params.value());
|
||||
|
||||
service::Document& document_service = context.GetService<service::Document>();
|
||||
document_service.UpdateDocument(did_change_text_document_params);
|
||||
document_service.UpdateDocument(params);
|
||||
|
||||
spdlog::info("Document updated: {}", did_change_text_document_params.textDocument.uri);
|
||||
spdlog::info("Document updated: {}", params.textDocument.uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DidChange : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
|
||||
std::string DidClose::GetMethod() const
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DidClose : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../protocol/transform/facade.hpp"
|
||||
#include "../../service/document.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string DidOpen::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DidOpen : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./document_color.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string DocumentColor::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DocumentColor : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./document_highlight.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string DocumentHighlight::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DocumentHighlight : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./document_link.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string DocumentLink::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DocumentLink : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./document_symbol.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string DocumentSymbol::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class DocumentSymbol : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./folding_range.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string FoldingRange::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class FoldingRange : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./formatting.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Formatting::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Formatting : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./hover.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Hover::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Hover : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./implementation.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Implementation::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Implementation : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./inlay_hint.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string InlayHint::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class InlayHint : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./inline_value.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string InlineValue::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class InlineValue : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./linked_editing_range.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string LinkedEditingRange::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class LinkedEditingRange : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./moniker.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string Moniker::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class Moniker : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./on_type_formatting.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string OnTypeFormatting::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class OnTypeFormatting : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./prepare_call_hierarchy.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string PrepareCallHierarchy::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class PrepareCallHierarchy : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./prepare_rename.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string PrepareRename::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class PrepareRename : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./prepare_type_hierarchy.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string PrepareTypeHierarchy::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class PrepareTypeHierarchy : public IRequestProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./publish_diagnostics.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string PublishDiagnostics::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
#include "../base/interface.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
class PublishDiagnostics : public INotificationProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "./range_formatting.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::text_document
|
||||
namespace lsp::provider::text_document
|
||||
{
|
||||
std::string RangeFormatting::GetMethod() const
|
||||
{
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue