146 lines
4.9 KiB
C++
146 lines
4.9 KiB
C++
#include <spdlog/spdlog.h>
|
|
#include "./references.hpp"
|
|
#include "../../protocol/transform/facade.hpp"
|
|
#include "../../service/document.hpp"
|
|
#include "../../service/symbol.hpp"
|
|
|
|
namespace lsp::provider::text_document
|
|
{
|
|
std::string References::GetMethod() const
|
|
{
|
|
return "textDocument/references";
|
|
}
|
|
|
|
std::string References::GetProviderName() const
|
|
{
|
|
return "TextDocumentReferences";
|
|
}
|
|
|
|
std::string References::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
|
|
{
|
|
spdlog::debug("TextDocumentReferencesProvider: Providing response for method {}", request.method);
|
|
|
|
if (!request.params.has_value())
|
|
{
|
|
spdlog::warn("{}: Missing params in request", GetProviderName());
|
|
return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInvalidParams, "Missing params");
|
|
}
|
|
|
|
protocol::ReferenceParams params =
|
|
transform::As<protocol::ReferenceParams>(request.params.value());
|
|
|
|
auto locations = BuildReferencesResponse(params, context);
|
|
|
|
protocol::ResponseMessage response;
|
|
response.id = request.id;
|
|
|
|
if (!locations.empty())
|
|
response.result = transform::LSPAny(locations);
|
|
else
|
|
response.result = transform::LSPAny(std::vector<protocol::Location>{});
|
|
|
|
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();
|
|
}
|
|
|
|
std::vector<protocol::Location> References::BuildReferencesResponse(const protocol::ReferenceParams& params, ExecutionContext& context)
|
|
{
|
|
spdlog::trace("{}: Processing references request for URI='{}', Position=({}, {})",
|
|
GetProviderName(),
|
|
params.textDocument.uri,
|
|
params.position.line,
|
|
params.position.character);
|
|
|
|
std::string identifier = GetIdentifierAtPosition(
|
|
params.textDocument.uri, params.position, context);
|
|
|
|
if (identifier.empty())
|
|
{
|
|
spdlog::info("{}: No identifier at position", GetProviderName());
|
|
return {};
|
|
}
|
|
|
|
spdlog::debug("{}: Looking for references of '{}'", GetProviderName(), identifier);
|
|
|
|
auto locations = FindReferences(params.textDocument.uri, identifier, params.context.includeDeclaration, context);
|
|
spdlog::info("{}: Found {} references", GetProviderName(), locations.size());
|
|
|
|
return locations;
|
|
}
|
|
|
|
std::vector<protocol::Location> References::FindReferences(const protocol::DocumentUri& uri, const std::string& identifier, bool include_declaration, ExecutionContext& context)
|
|
{
|
|
std::vector<protocol::Location> locations;
|
|
|
|
// 从容器获取文档服务
|
|
auto& document_service = context.GetService<service::Document>();
|
|
|
|
auto content = document_service.GetContent(uri);
|
|
auto tree = document_service.GetSyntaxTree(uri);
|
|
|
|
if (!content.has_value() || !tree)
|
|
{
|
|
spdlog::warn("{}: Document not found or no syntax tree: {}", GetProviderName(), uri);
|
|
return locations;
|
|
}
|
|
|
|
TSNode root = ts_tree_root_node(tree);
|
|
FindReferencesInNode(root, identifier, *content, uri, locations, include_declaration);
|
|
|
|
return locations;
|
|
}
|
|
|
|
std::string References::GetIdentifierAtPosition(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context)
|
|
{
|
|
auto& document_service = context.GetService<service::Document>();
|
|
|
|
auto content = document_service.GetContent(uri);
|
|
auto tree = document_service.GetSyntaxTree(uri);
|
|
|
|
if (!content.has_value() || !tree)
|
|
return "";
|
|
|
|
size_t byte_offset = 0;
|
|
size_t current_line = 0;
|
|
size_t current_col = 0;
|
|
|
|
for (size_t i = 0; i < content->length(); i++)
|
|
{
|
|
if (current_line == position.line && current_col == position.character)
|
|
{
|
|
byte_offset = i;
|
|
break;
|
|
}
|
|
|
|
if ((*content)[i] == '\n')
|
|
{
|
|
current_line++;
|
|
current_col = 0;
|
|
}
|
|
else
|
|
{
|
|
current_col++;
|
|
}
|
|
}
|
|
|
|
TSNode root = ts_tree_root_node(tree);
|
|
TSNode node = ts_node_descendant_for_byte_range(root, byte_offset, byte_offset);
|
|
|
|
while (!ts_node_is_null(node))
|
|
{
|
|
const char* node_type = ts_node_type(node);
|
|
if (strcmp(node_type, kIdentifier) == 0)
|
|
{
|
|
uint32_t start = ts_node_start_byte(node);
|
|
uint32_t end = ts_node_end_byte(node);
|
|
return content->substr(start, end - start);
|
|
}
|
|
node = ts_node_parent(node);
|
|
}
|
|
|
|
return "";
|
|
}
|
|
}
|