♻️ 使用module重构所有代码
This commit is contained in:
@@ -15,23 +15,77 @@ if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
|
||||
|
||||
set(SOURCES
|
||||
test.cpp
|
||||
debug_printer.cpp
|
||||
test.cppm
|
||||
../../src/utils/string.cppm
|
||||
../../src/utils/string.cpp
|
||||
../../src/language/ast/deserializer.cpp
|
||||
../../src/language/ast/detail.cpp
|
||||
../../src/language/ast/tree_sitter_utils.cpp
|
||||
../../src/language/symbol/builder.cpp
|
||||
../../src/language/symbol/store.cpp
|
||||
../../src/language/symbol/table.cpp
|
||||
../../src/language/symbol/index/coordinator.cpp
|
||||
../../src/language/symbol/index/location.cpp
|
||||
../../src/language/symbol/index/scope.cpp
|
||||
../../src/language/symbol/internal/builder.cppm
|
||||
../../src/language/symbol/internal/store.cppm
|
||||
../../src/language/symbol/internal/table.cppm
|
||||
../../src/language/symbol/index/coordinator.cppm
|
||||
../../src/language/symbol/index/location.cppm
|
||||
../../src/language/symbol/index/scope.cppm
|
||||
../../src/tree-sitter/scanner.c
|
||||
../../src/tree-sitter/parser.c)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
if(TARGET std_module)
|
||||
add_dependencies(${PROJECT_NAME} std_module)
|
||||
endif()
|
||||
target_sources(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
FILE_SET cxx_modules TYPE CXX_MODULES
|
||||
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
FILES ../../src/bridge/tree_sitter.cppm
|
||||
../../src/bridge/spdlog.cppm
|
||||
../../src/bridge/glaze.cppm
|
||||
../../src/language/ast/ast.cppm
|
||||
../../src/language/ast/types.cppm
|
||||
../../src/language/ast/deserializer.cppm
|
||||
../../src/language/ast/deserializer_impl.cppm
|
||||
../../src/language/ast/ts_utils.cppm
|
||||
../../src/language/ast/detail.cppm
|
||||
../../src/utils/string.cppm
|
||||
../../src/protocol/common/basic_types.cppm
|
||||
../../src/protocol/common/message.cppm
|
||||
../../src/protocol/common/registration.cppm
|
||||
../../src/protocol/window/progress.cppm
|
||||
../../src/protocol/initialize/configuration.cppm
|
||||
../../src/protocol/initialize/capabilities.cppm
|
||||
../../src/protocol/workspace/workspace.cppm
|
||||
../../src/protocol/workspace/file_operations.cppm
|
||||
../../src/protocol/workspace/notebook.cppm
|
||||
../../src/protocol/text_document/document_sync.cppm
|
||||
../../src/protocol/text_document/completion.cppm
|
||||
../../src/protocol/text_document/code_actions.cppm
|
||||
../../src/protocol/text_document/diagnostics.cppm
|
||||
../../src/protocol/text_document/document_features.cppm
|
||||
../../src/protocol/text_document/formatting.cppm
|
||||
../../src/protocol/text_document/inline_features.cppm
|
||||
../../src/protocol/text_document/navigation.cppm
|
||||
../../src/protocol/text_document/rename.cppm
|
||||
../../src/protocol/text_document/semantic_tokens.cppm
|
||||
../../src/protocol/text_document/signature_help.cppm
|
||||
../../src/protocol/text_document/symbols.cppm
|
||||
../../src/codec/common.cppm
|
||||
../../src/codec/transformer.cppm
|
||||
../../src/codec/facade.cppm
|
||||
../../src/protocol/types.cppm
|
||||
../../src/protocol/protocol.cppm
|
||||
../../src/language/symbol/types.cppm
|
||||
../../src/language/symbol/internal/builder.cppm
|
||||
../../src/language/symbol/internal/store.cppm
|
||||
../../src/language/symbol/internal/table.cppm
|
||||
../../src/language/symbol/index/coordinator.cppm
|
||||
../../src/language/symbol/index/location.cppm
|
||||
../../src/language/symbol/index/scope.cppm
|
||||
../../src/language/symbol/symbol.cppm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/debug_printer.cppm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test.cppm)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
||||
@@ -43,8 +97,9 @@ target_link_libraries(
|
||||
fmt::fmt-header-only tree-sitter::tree-sitter
|
||||
$<$<PLATFORM_ID:Linux>:Threads::Threads>)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(
|
||||
${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic $<$<CONFIG:Debug>:-g -O0>
|
||||
$<$<CONFIG:Release>:-O3>)
|
||||
endif()
|
||||
target_compile_options(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
-Wall -Wextra -Wpedantic $<$<CONFIG:Debug>:-g -O0>
|
||||
-Wno-import-implementation-partition-unit-in-interface-unit
|
||||
$<$<CONFIG:Release>:-O3>)
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "./debug_printer.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace lsp::language;
|
||||
using namespace lsp::language::symbol;
|
||||
|
||||
const char* AccessModifierToString(ast::AccessModifier access)
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case ast::AccessModifier::kPublic:
|
||||
return "public";
|
||||
case ast::AccessModifier::kProtected:
|
||||
return "protected";
|
||||
case ast::AccessModifier::kPrivate:
|
||||
return "private";
|
||||
}
|
||||
return "public";
|
||||
}
|
||||
|
||||
const char* VariableScopeToString(VariableScope scope)
|
||||
{
|
||||
switch (scope)
|
||||
{
|
||||
case VariableScope::kAutomatic:
|
||||
return "auto";
|
||||
case VariableScope::kStatic:
|
||||
return "static";
|
||||
case VariableScope::kGlobal:
|
||||
return "global";
|
||||
case VariableScope::kParameter:
|
||||
return "param";
|
||||
case VariableScope::kField:
|
||||
return "field";
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace lsp::language::symbol::debug
|
||||
{
|
||||
namespace Color
|
||||
{
|
||||
constexpr const char* Reset = "\033[0m";
|
||||
constexpr const char* Bold = "\033[1m";
|
||||
constexpr const char* Dim = "\033[2m";
|
||||
constexpr const char* Red = "\033[31m";
|
||||
constexpr const char* Green = "\033[32m";
|
||||
constexpr const char* Yellow = "\033[33m";
|
||||
constexpr const char* Blue = "\033[34m";
|
||||
constexpr const char* Magenta = "\033[35m";
|
||||
constexpr const char* Cyan = "\033[36m";
|
||||
constexpr const char* White = "\033[37m";
|
||||
constexpr const char* BrightBlue = "\033[94m";
|
||||
constexpr const char* BrightMagenta = "\033[95m";
|
||||
constexpr const char* BrightGreen = "\033[92m";
|
||||
constexpr const char* Gray = "\033[90m";
|
||||
}
|
||||
|
||||
// ==================== PrintOptions ====================
|
||||
|
||||
PrintOptions PrintOptions::Default()
|
||||
{
|
||||
return PrintOptions{};
|
||||
}
|
||||
|
||||
PrintOptions PrintOptions::Compact()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.compact_mode = true;
|
||||
opts.show_details = false;
|
||||
opts.show_children = false;
|
||||
opts.indent_size = 1;
|
||||
return opts;
|
||||
}
|
||||
|
||||
PrintOptions PrintOptions::Verbose()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.show_details = true;
|
||||
opts.show_children = true;
|
||||
return opts;
|
||||
}
|
||||
|
||||
PrintOptions PrintOptions::NoColor()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.use_color = false;
|
||||
return opts;
|
||||
}
|
||||
|
||||
// ==================== Statistics ====================
|
||||
|
||||
void Statistics::Compute(const SymbolTable& table)
|
||||
{
|
||||
auto all_defs = table.all_definitions();
|
||||
total_symbols = all_defs.size();
|
||||
|
||||
symbol_counts.clear();
|
||||
scope_counts.clear();
|
||||
|
||||
for (const auto& ref : all_defs)
|
||||
{
|
||||
const auto& sym = ref.get();
|
||||
symbol_counts[sym.kind()]++;
|
||||
}
|
||||
|
||||
const auto& scopes = table.scopes().all_scopes();
|
||||
total_scopes = scopes.size();
|
||||
for (const auto& [_, info] : scopes)
|
||||
{
|
||||
scope_counts[info.kind]++;
|
||||
}
|
||||
}
|
||||
|
||||
void Statistics::Print(std::ostream& os, bool use_color) const
|
||||
{
|
||||
auto color = [use_color](const char* code) {
|
||||
return use_color ? code : "";
|
||||
};
|
||||
|
||||
os << "\n";
|
||||
os << color(Color::Bold) << "╔════════════════════════════════════════════════════════════╗\n";
|
||||
os << "║ STATISTICS ║\n";
|
||||
os << "╚════════════════════════════════════════════════════════════╝"
|
||||
<< color(Color::Reset) << "\n\n";
|
||||
|
||||
os << color(Color::Bold) << "Overview:" << color(Color::Reset) << "\n";
|
||||
os << " Total Symbols: " << color(Color::Cyan) << total_symbols << color(Color::Reset) << "\n";
|
||||
os << " Total Scopes: " << color(Color::Cyan) << total_scopes << color(Color::Reset) << "\n";
|
||||
os << "\n";
|
||||
|
||||
os << color(Color::Bold) << "Symbol Distribution:" << color(Color::Reset) << "\n";
|
||||
|
||||
struct KindInfo
|
||||
{
|
||||
SymbolKind kind;
|
||||
const char* name;
|
||||
const char* icon;
|
||||
};
|
||||
|
||||
KindInfo kinds[] = {
|
||||
{ SymbolKind::Module, "Module", "🗃️" },
|
||||
{ SymbolKind::Class, "Classes", "🏛️" },
|
||||
{ SymbolKind::Function, "Functions", "🎄" },
|
||||
{ SymbolKind::Method, "Methods", "🪀" },
|
||||
{ SymbolKind::Property, "Properties", "📋" },
|
||||
{ SymbolKind::Field, "Fields", "📌" },
|
||||
{ SymbolKind::Variable, "Variables", "📊" },
|
||||
{ SymbolKind::Constant, "Constants", "🔒" }
|
||||
};
|
||||
|
||||
for (const auto& kind_info : kinds)
|
||||
{
|
||||
auto it = symbol_counts.find(kind_info.kind);
|
||||
if (it != symbol_counts.end() && it->second > 0)
|
||||
{
|
||||
os << " " << kind_info.icon << " "
|
||||
<< std::setw(15) << std::left << kind_info.name
|
||||
<< ": " << color(Color::BrightBlue) << std::setw(5) << std::right
|
||||
<< it->second << color(Color::Reset) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!scope_counts.empty())
|
||||
{
|
||||
os << "\n"
|
||||
<< color(Color::Bold) << "Scope Distribution:" << color(Color::Reset) << "\n";
|
||||
for (const auto& [kind, count] : scope_counts)
|
||||
{
|
||||
os << " " << std::setw(12) << std::left << static_cast<int>(kind)
|
||||
<< ": " << color(Color::BrightMagenta) << count << color(Color::Reset) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== DebugPrinter ====================
|
||||
|
||||
DebugPrinter::DebugPrinter(const SymbolTable& table, const PrintOptions& options) : table_(table), options_(options)
|
||||
{
|
||||
stats_.Compute(table_);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const
|
||||
{
|
||||
for (int i = 0; i < width; ++i)
|
||||
os << ch;
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Color(const char* color_code) const
|
||||
{
|
||||
return options_.use_color ? color_code : "";
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Bold(const std::string& text) const
|
||||
{
|
||||
return options_.use_color ? std::string(Color::Bold) + text + Color::Reset : text;
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Dim(const std::string& text) const
|
||||
{
|
||||
return options_.use_color ? std::string(Color::Dim) + text + Color::Reset : text;
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Indent(int depth) const
|
||||
{
|
||||
return std::string(static_cast<size_t>(depth * options_.indent_size), ' ');
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatLocation(const ast::Location& loc) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << loc.start_line << ":" << loc.start_column << "-" << loc.end_line << ":" << loc.end_column;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatSymbolKind(SymbolKind kind) const
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case SymbolKind::Module:
|
||||
return "Module";
|
||||
case SymbolKind::Class:
|
||||
return "Class";
|
||||
case SymbolKind::Method:
|
||||
return "Method";
|
||||
case SymbolKind::Property:
|
||||
return "Property";
|
||||
case SymbolKind::Field:
|
||||
return "Field";
|
||||
case SymbolKind::Function:
|
||||
return "Function";
|
||||
case SymbolKind::Variable:
|
||||
return "Variable";
|
||||
case SymbolKind::Constant:
|
||||
return "Constant";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatScopeKind(ScopeKind kind) const
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ScopeKind::kGlobal:
|
||||
return "Global";
|
||||
case ScopeKind::kUnit:
|
||||
return "Unit";
|
||||
case ScopeKind::kClass:
|
||||
return "Class";
|
||||
case ScopeKind::kFunction:
|
||||
return "Function";
|
||||
case ScopeKind::kAnonymousFunction:
|
||||
return "AnonymousFunction";
|
||||
case ScopeKind::kBlock:
|
||||
return "Block";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string DebugPrinter::SymbolIcon(SymbolKind kind) const
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case SymbolKind::Module:
|
||||
return "🗃️";
|
||||
case SymbolKind::Class:
|
||||
return "🏛️";
|
||||
case SymbolKind::Method:
|
||||
return "🔧"; // Default, will be overridden in GetSymbolIcon
|
||||
case SymbolKind::Property:
|
||||
return "📋";
|
||||
case SymbolKind::Field:
|
||||
return "📌";
|
||||
case SymbolKind::Function:
|
||||
return "🌲"; // Default, will be overridden in GetSymbolIcon
|
||||
case SymbolKind::Variable:
|
||||
return "📊";
|
||||
case SymbolKind::Constant:
|
||||
return "🔒";
|
||||
default:
|
||||
return "❓";
|
||||
}
|
||||
}
|
||||
|
||||
std::string DebugPrinter::GetSymbolIcon(const Symbol& symbol) const
|
||||
{
|
||||
// Check if it's a Method with declaration/implementation distinction
|
||||
if (const auto* method = symbol.As<Method>())
|
||||
{
|
||||
bool has_decl = method->declaration_range.start_line != 0;
|
||||
bool has_impl = method->implementation_range.has_value();
|
||||
|
||||
if (has_decl && has_impl)
|
||||
{
|
||||
// Has both declaration and implementation
|
||||
if (symbol.selection_range().start_line == method->declaration_range.start_line)
|
||||
{
|
||||
return "🔷"; // Declaration: blue diamond (interface/contract)
|
||||
}
|
||||
else if (has_impl && symbol.selection_range().start_line == method->implementation_range->start_line)
|
||||
{
|
||||
return "🔶"; // Implementation: orange diamond (concrete/실행)
|
||||
}
|
||||
}
|
||||
return "🔧"; // Default method icon (wrench/tool)
|
||||
}
|
||||
|
||||
// Check if it's a Function with declaration/implementation distinction
|
||||
if (const auto* func = symbol.As<Function>())
|
||||
{
|
||||
bool has_decl = func->declaration_range.start_line != 0;
|
||||
bool has_impl = func->implementation_range.has_value();
|
||||
|
||||
if (has_decl && has_impl)
|
||||
{
|
||||
// Has both declaration and implementation
|
||||
if (symbol.selection_range().start_line == func->declaration_range.start_line)
|
||||
{
|
||||
return "🌳"; // Declaration: deciduous tree (interface/skeleton)
|
||||
}
|
||||
else if (has_impl && symbol.selection_range().start_line == func->implementation_range->start_line)
|
||||
{
|
||||
return "🎄"; // Implementation: christmas tree (decorated/complete)
|
||||
}
|
||||
}
|
||||
return "🌲"; // Default function icon (evergreen tree)
|
||||
}
|
||||
|
||||
// For other types, use the default icon
|
||||
return SymbolIcon(symbol.kind());
|
||||
}
|
||||
|
||||
std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const
|
||||
{
|
||||
return Color(Color::Blue) + FormatSymbolKind(kind) + Color(Color::Reset);
|
||||
}
|
||||
|
||||
std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind /*kind*/) const
|
||||
{
|
||||
return Color(Color::Yellow) + name + Color(Color::Reset);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintHeader(const std::string& title, std::ostream& os) const
|
||||
{
|
||||
os << "\n"
|
||||
<< Bold(title) << "\n";
|
||||
PrintSeparator(os, '=', 60);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSubHeader(const std::string& title, std::ostream& os) const
|
||||
{
|
||||
os << "\n"
|
||||
<< Bold(title) << "\n";
|
||||
PrintSeparator(os, '-', 40);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth)
|
||||
{
|
||||
std::visit(
|
||||
[&](const auto& data) {
|
||||
// Tree connector prefix based on depth
|
||||
std::string prefix;
|
||||
if (depth > 0)
|
||||
{
|
||||
prefix = Indent(depth - 1) + Color(Color::Gray) + "├─ " + Color(Color::Reset);
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
os << prefix << GetSymbolIcon(symbol) << " "
|
||||
<< ColorizeSymbolName(symbol.name(), symbol.kind())
|
||||
<< " " << Color(Color::Dim) << "(" << FormatSymbolKind(symbol.kind()) << ")" << Color(Color::Reset);
|
||||
|
||||
if (options_.show_location)
|
||||
{
|
||||
os << " " << Color(Color::Gray) << "@ " << FormatLocation(symbol.selection_range()) << Color(Color::Reset);
|
||||
}
|
||||
|
||||
// Type-specific details
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Function>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
os << " " << Color(Color::BrightGreen) << "→ " << (data.return_type ? *data.return_type : "void") << Color(Color::Reset);
|
||||
if (!data.parameters.empty())
|
||||
{
|
||||
os << " " << Color(Color::Dim) << "(";
|
||||
for (size_t i = 0; i < data.parameters.size(); ++i)
|
||||
{
|
||||
const auto& p = data.parameters[i];
|
||||
os << p.name;
|
||||
if (p.type)
|
||||
os << ":" << *p.type;
|
||||
if (i + 1 < data.parameters.size())
|
||||
os << ", ";
|
||||
}
|
||||
os << ")" << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Method>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset);
|
||||
|
||||
if (data.is_static)
|
||||
os << " " << Color(Color::Yellow) << "static" << Color(Color::Reset);
|
||||
|
||||
if (data.return_type)
|
||||
os << " " << Color(Color::BrightGreen) << "→ " << *data.return_type << Color(Color::Reset);
|
||||
|
||||
if (!data.parameters.empty())
|
||||
{
|
||||
os << " " << Color(Color::Dim) << "(";
|
||||
for (size_t i = 0; i < data.parameters.size(); ++i)
|
||||
{
|
||||
const auto& p = data.parameters[i];
|
||||
os << p.name;
|
||||
if (p.type)
|
||||
os << ":" << *p.type;
|
||||
if (i + 1 < data.parameters.size())
|
||||
os << ", ";
|
||||
}
|
||||
os << ")" << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Property>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset);
|
||||
if (data.type)
|
||||
os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Field>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset);
|
||||
if (data.type)
|
||||
os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset);
|
||||
if (data.is_static)
|
||||
os << " " << Color(Color::Yellow) << "static" << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Variable>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
os << " " << Color(Color::Dim) << "(" << VariableScopeToString(data.storage) << ")" << Color(Color::Reset);
|
||||
if (data.type)
|
||||
os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset);
|
||||
if (data.has_initializer)
|
||||
os << " " << Color(Color::Gray) << "= ..." << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::decay_t<decltype(data)>, Constant>)
|
||||
{
|
||||
if (options_.show_details)
|
||||
{
|
||||
if (data.type)
|
||||
os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset);
|
||||
os << " " << Color(Color::Gray) << "= " << data.value << Color(Color::Reset);
|
||||
}
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
},
|
||||
symbol.data());
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth)
|
||||
{
|
||||
const auto* sym = table_.definition(id);
|
||||
if (!sym)
|
||||
{
|
||||
os << Indent(depth) << "❓ Unknown symbol: " << id << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
PrintSymbolData(*sym, os, depth);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap<SymbolId, SymbolId>& children, std::ostream& os, int depth, int current_depth)
|
||||
{
|
||||
if (options_.max_depth >= 0 && current_depth > options_.max_depth)
|
||||
return;
|
||||
|
||||
PrintSymbol(id, os, depth);
|
||||
|
||||
if (!options_.show_children)
|
||||
return;
|
||||
|
||||
auto range = children.equal_range(id);
|
||||
std::vector<SymbolId> child_list;
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
{
|
||||
child_list.push_back(it->second);
|
||||
}
|
||||
|
||||
// Sort children by location for consistent output
|
||||
std::sort(child_list.begin(), child_list.end(), [this](SymbolId a, SymbolId b) {
|
||||
const auto* sym_a = table_.definition(a);
|
||||
const auto* sym_b = table_.definition(b);
|
||||
if (!sym_a || !sym_b)
|
||||
return a < b;
|
||||
|
||||
auto loc_a = sym_a->selection_range();
|
||||
auto loc_b = sym_b->selection_range();
|
||||
|
||||
if (loc_a.start_line != loc_b.start_line)
|
||||
return loc_a.start_line < loc_b.start_line;
|
||||
return loc_a.start_column < loc_b.start_column;
|
||||
});
|
||||
|
||||
for (auto child_id : child_list)
|
||||
{
|
||||
PrintSymbolWithChildren(child_id, children, os, depth + 1, current_depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth)
|
||||
{
|
||||
std::unordered_multimap<SymbolId, SymbolId> children;
|
||||
for (const auto& [scope_id, scope] : table_.scopes().all_scopes())
|
||||
{
|
||||
if (scope.owner)
|
||||
{
|
||||
for (const auto& [_, sym_ids] : scope.symbols)
|
||||
{
|
||||
for (auto sym_id : sym_ids)
|
||||
{
|
||||
children.emplace(*scope.owner, sym_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrintSymbolWithChildren(id, children, os, depth, 0);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolList(std::ostream& os)
|
||||
{
|
||||
PrintHeader("Symbols", os);
|
||||
|
||||
auto all_defs = table_.all_definitions();
|
||||
|
||||
// Group symbols by their parent (class/namespace)
|
||||
std::unordered_multimap<SymbolId, SymbolId> children;
|
||||
std::unordered_set<SymbolId> has_parent;
|
||||
|
||||
for (const auto& [scope_id, scope] : table_.scopes().all_scopes())
|
||||
{
|
||||
if (scope.owner)
|
||||
{
|
||||
for (const auto& [_, sym_ids] : scope.symbols)
|
||||
{
|
||||
for (auto sym_id : sym_ids)
|
||||
{
|
||||
children.emplace(*scope.owner, sym_id);
|
||||
has_parent.insert(sym_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find top-level symbols (no parent)
|
||||
std::vector<const Symbol*> top_level;
|
||||
for (const auto& ref : all_defs)
|
||||
{
|
||||
const auto& sym = ref.get();
|
||||
if (has_parent.find(sym.id()) == has_parent.end())
|
||||
{
|
||||
top_level.push_back(&sym);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort top-level symbols by location
|
||||
std::sort(top_level.begin(), top_level.end(), [](const Symbol* a, const Symbol* b) {
|
||||
auto loc_a = a->selection_range();
|
||||
auto loc_b = b->selection_range();
|
||||
if (loc_a.start_line != loc_b.start_line)
|
||||
return loc_a.start_line < loc_b.start_line;
|
||||
return loc_a.start_column < loc_b.start_column;
|
||||
});
|
||||
|
||||
// Print each top-level symbol with its children
|
||||
for (const auto* sym : top_level)
|
||||
{
|
||||
PrintSymbolWithChildren(sym->id(), children, os, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os)
|
||||
{
|
||||
PrintSubHeader("Symbols of kind: " + FormatSymbolKind(kind), os);
|
||||
auto all_defs = table_.all_definitions();
|
||||
for (const auto& ref : all_defs)
|
||||
{
|
||||
const auto& sym = ref.get();
|
||||
if (sym.kind() == kind)
|
||||
{
|
||||
PrintSymbolData(sym, os, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth)
|
||||
{
|
||||
const auto* scope = table_.scopes().scope(id);
|
||||
if (!scope)
|
||||
{
|
||||
os << Indent(depth) << "❓ Unknown scope: " << id << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
os << Indent(depth) << "📁 " << FormatScopeKind(scope->kind)
|
||||
<< " (id=" << id << ")";
|
||||
if (scope->owner)
|
||||
{
|
||||
os << " owner=" << *scope->owner;
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
for (const auto& [name, sym_ids] : scope->symbols)
|
||||
{
|
||||
for (auto sym_id : sym_ids)
|
||||
{
|
||||
os << Indent(depth + 1) << "• " << name << " (id=" << sym_id << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth)
|
||||
{
|
||||
const auto& all_scopes = table_.scopes().all_scopes();
|
||||
std::unordered_multimap<ScopeId, ScopeId> children;
|
||||
for (const auto& [scope_id, scope] : all_scopes)
|
||||
{
|
||||
if (scope.parent)
|
||||
{
|
||||
children.emplace(*scope.parent, scope_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(ScopeId, int)> dfs = [&](ScopeId sid, int d) {
|
||||
PrintScope(sid, os, d);
|
||||
auto range = children.equal_range(sid);
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
{
|
||||
dfs(it->second, d + 1);
|
||||
}
|
||||
};
|
||||
|
||||
dfs(id, depth);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScopeHierarchy(std::ostream& os)
|
||||
{
|
||||
PrintHeader("Scopes", os);
|
||||
const auto& scopes = table_.scopes().all_scopes();
|
||||
if (scopes.empty())
|
||||
{
|
||||
os << "No scopes available\n";
|
||||
return;
|
||||
}
|
||||
|
||||
auto global = table_.scopes().global_scope();
|
||||
if (global == kInvalidScopeId && !scopes.empty())
|
||||
{
|
||||
global = scopes.begin()->first;
|
||||
}
|
||||
PrintScopeTree(global, os, 0);
|
||||
}
|
||||
|
||||
void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os)
|
||||
{
|
||||
PrintHeader("Search: " + name, os);
|
||||
auto matches = table_.FindSymbolsByName(name);
|
||||
if (matches.empty())
|
||||
{
|
||||
os << "No symbols found matching \"" << name << "\"\n";
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto id : matches)
|
||||
{
|
||||
PrintSymbol(id, os);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os)
|
||||
{
|
||||
auto id = table_.FindSymbolAt(loc);
|
||||
if (!id)
|
||||
{
|
||||
os << "No symbol found at location " << FormatLocation(loc) << "\n";
|
||||
return;
|
||||
}
|
||||
PrintSymbol(*id, os);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintOverview(std::ostream& os)
|
||||
{
|
||||
PrintHeader("Overview", os);
|
||||
os << "Symbols: " << stats_.total_symbols << "\n";
|
||||
os << "Scopes: " << stats_.total_scopes << "\n";
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintStatistics(std::ostream& os)
|
||||
{
|
||||
stats_.Print(os, options_.use_color);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintAll(std::ostream& os)
|
||||
{
|
||||
PrintOverview(os);
|
||||
PrintSymbolList(os);
|
||||
PrintScopeHierarchy(os);
|
||||
PrintStatistics(os);
|
||||
}
|
||||
|
||||
// ==================== Free functions ====================
|
||||
|
||||
void Print(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
printer.PrintAll(os);
|
||||
}
|
||||
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
printer.PrintOverview(os);
|
||||
}
|
||||
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
printer.PrintStatistics(os);
|
||||
}
|
||||
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
auto defs = table.all_definitions();
|
||||
for (const auto& ref : defs)
|
||||
{
|
||||
printer.PrintSymbolTree(ref.get().id(), os);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
printer.PrintScopeHierarchy(os);
|
||||
}
|
||||
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Default());
|
||||
printer.FindAndPrint(name, os);
|
||||
}
|
||||
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Compact());
|
||||
printer.PrintOverview(os);
|
||||
printer.PrintSymbolList(os);
|
||||
}
|
||||
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Verbose());
|
||||
printer.PrintAll(os);
|
||||
}
|
||||
|
||||
} // namespace lsp::language::symbol::debug
|
||||
@@ -0,0 +1,474 @@
|
||||
module;
|
||||
|
||||
import std;
|
||||
|
||||
export module lsp.test.symbol.debug_printer;
|
||||
|
||||
import lsp.protocol;
|
||||
import lsp.language.ast;
|
||||
import lsp.language.symbol;
|
||||
|
||||
export namespace lsp::language::symbol::debug
|
||||
{
|
||||
using SymbolKind = protocol::SymbolKind;
|
||||
|
||||
struct PrintOptions
|
||||
{
|
||||
bool use_color = true;
|
||||
bool show_location = true;
|
||||
bool show_details = true;
|
||||
bool show_children = true;
|
||||
bool compact_mode = false;
|
||||
int indent_size = 2;
|
||||
int max_depth = -1;
|
||||
|
||||
static PrintOptions Default()
|
||||
{
|
||||
return PrintOptions();
|
||||
}
|
||||
|
||||
static PrintOptions Compact()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.compact_mode = true;
|
||||
opts.show_children = true;
|
||||
opts.show_details = false;
|
||||
opts.indent_size = 0;
|
||||
return opts;
|
||||
}
|
||||
|
||||
static PrintOptions Verbose()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.show_children = true;
|
||||
opts.show_details = true;
|
||||
return opts;
|
||||
}
|
||||
|
||||
static PrintOptions NoColor()
|
||||
{
|
||||
PrintOptions opts;
|
||||
opts.use_color = false;
|
||||
return opts;
|
||||
}
|
||||
};
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
std::size_t total_symbols = 0;
|
||||
std::size_t total_scopes = 0;
|
||||
|
||||
std::unordered_map<SymbolKind, std::size_t> symbol_counts;
|
||||
std::unordered_map<ScopeKind, std::size_t> scope_counts;
|
||||
|
||||
void Compute(const SymbolTable& table);
|
||||
void Print(std::ostream& os, bool use_color = true) const;
|
||||
};
|
||||
|
||||
class DebugPrinter
|
||||
{
|
||||
public:
|
||||
explicit DebugPrinter(const SymbolTable& table, const PrintOptions& options = PrintOptions::Default());
|
||||
|
||||
void PrintAll(std::ostream& os = std::cout);
|
||||
void PrintOverview(std::ostream& os = std::cout);
|
||||
void PrintStatistics(std::ostream& os = std::cout);
|
||||
|
||||
void PrintSymbol(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolTree(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolList(std::ostream& os = std::cout);
|
||||
void PrintSymbolsByKind(SymbolKind kind, std::ostream& os = std::cout);
|
||||
|
||||
void PrintScope(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeTree(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeHierarchy(std::ostream& os = std::cout);
|
||||
|
||||
void FindAndPrint(const std::string& name, std::ostream& os = std::cout);
|
||||
void FindAtLocation(const ast::Location& loc, std::ostream& os = std::cout);
|
||||
|
||||
void SetOptions(const PrintOptions& options) { options_ = options; }
|
||||
const PrintOptions& GetOptions() const { return options_; }
|
||||
|
||||
private:
|
||||
const SymbolTable& table_;
|
||||
PrintOptions options_;
|
||||
Statistics stats_;
|
||||
|
||||
std::string Indent(int depth) const;
|
||||
std::string ColorizeSymbolKind(SymbolKind kind) const;
|
||||
std::string ColorizeSymbolName(const std::string& name, SymbolKind kind) const;
|
||||
std::string FormatLocation(const ast::Location& loc) const;
|
||||
std::string FormatSymbolKind(SymbolKind kind) const;
|
||||
std::string FormatScopeKind(ScopeKind kind) const;
|
||||
std::string SymbolIcon(SymbolKind kind) const;
|
||||
|
||||
void PrintSeparator(std::ostream& os, char ch = '=', int width = 80) const;
|
||||
void PrintHeader(const std::string& title, std::ostream& os) const;
|
||||
void PrintSubHeader(const std::string& title, std::ostream& os) const;
|
||||
|
||||
std::string Color(const char* color_code) const;
|
||||
std::string Bold(const std::string& text) const;
|
||||
std::string Dim(const std::string& text) const;
|
||||
|
||||
void PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth);
|
||||
void PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap<SymbolId, SymbolId>& children, std::ostream& os, int depth, int current_depth);
|
||||
std::string GetSymbolIcon(const Symbol& symbol) const;
|
||||
};
|
||||
|
||||
void Print(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os = std::cout);
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace lsp::language;
|
||||
using namespace lsp::language::symbol;
|
||||
using lsp::protocol::SymbolKind;
|
||||
|
||||
[[maybe_unused]] const char* AccessModifierToString(ast::AccessModifier access)
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case ast::AccessModifier::kPublic:
|
||||
return "public";
|
||||
case ast::AccessModifier::kProtected:
|
||||
return "protected";
|
||||
case ast::AccessModifier::kPrivate:
|
||||
return "private";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ScopeKindToString(ScopeKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ScopeKind::kGlobal:
|
||||
return "Global";
|
||||
case ScopeKind::kUnit:
|
||||
return "Unit";
|
||||
case ScopeKind::kClass:
|
||||
return "Class";
|
||||
case ScopeKind::kFunction:
|
||||
return "Function";
|
||||
case ScopeKind::kAnonymousFunction:
|
||||
return "AnonymousFunction";
|
||||
case ScopeKind::kBlock:
|
||||
return "Block";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string SymbolKindToString(SymbolKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case SymbolKind::File:
|
||||
return "File";
|
||||
case SymbolKind::Module:
|
||||
return "Module";
|
||||
case SymbolKind::Namespace:
|
||||
return "Namespace";
|
||||
case SymbolKind::Package:
|
||||
return "Package";
|
||||
case SymbolKind::Class:
|
||||
return "Class";
|
||||
case SymbolKind::Method:
|
||||
return "Method";
|
||||
case SymbolKind::Property:
|
||||
return "Property";
|
||||
case SymbolKind::Field:
|
||||
return "Field";
|
||||
case SymbolKind::Constructor:
|
||||
return "Constructor";
|
||||
case SymbolKind::Enum:
|
||||
return "Enum";
|
||||
case SymbolKind::Interface:
|
||||
return "Interface";
|
||||
case SymbolKind::Function:
|
||||
return "Function";
|
||||
case SymbolKind::Variable:
|
||||
return "Variable";
|
||||
case SymbolKind::Constant:
|
||||
return "Constant";
|
||||
case SymbolKind::String:
|
||||
return "String";
|
||||
case SymbolKind::Number:
|
||||
return "Number";
|
||||
case SymbolKind::Boolean:
|
||||
return "Boolean";
|
||||
case SymbolKind::Array:
|
||||
return "Array";
|
||||
case SymbolKind::Object:
|
||||
return "Object";
|
||||
case SymbolKind::Key:
|
||||
return "Key";
|
||||
case SymbolKind::Null:
|
||||
return "Null";
|
||||
case SymbolKind::EnumMember:
|
||||
return "EnumMember";
|
||||
case SymbolKind::Struct:
|
||||
return "Struct";
|
||||
case SymbolKind::Event:
|
||||
return "Event";
|
||||
case SymbolKind::Operator:
|
||||
return "Operator";
|
||||
case SymbolKind::TypeParameter:
|
||||
return "TypeParameter";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace lsp::language::symbol::debug
|
||||
{
|
||||
void Statistics::Compute(const SymbolTable& table)
|
||||
{
|
||||
total_symbols = table.all_definitions().size();
|
||||
total_scopes = 0;
|
||||
// 不再深入统计,避免依赖内部存储。
|
||||
}
|
||||
|
||||
DebugPrinter::DebugPrinter(const SymbolTable& table, const PrintOptions& options) :
|
||||
table_(table), options_(options)
|
||||
{
|
||||
stats_.Compute(table_);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintAll(std::ostream& os)
|
||||
{
|
||||
PrintOverview(os);
|
||||
os << "\n";
|
||||
PrintStatistics(os);
|
||||
os << "\nSymbols:\n";
|
||||
PrintSymbolList(os);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintOverview(std::ostream& os)
|
||||
{
|
||||
PrintHeader("Symbol Table Overview", os);
|
||||
os << "Total Symbols: " << stats_.total_symbols << "\n";
|
||||
os << "Total Scopes : " << stats_.total_scopes << "\n";
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintStatistics(std::ostream& os)
|
||||
{
|
||||
stats_.Print(os, options_.use_color);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth)
|
||||
{
|
||||
auto symbol = table_.definition(id);
|
||||
if (!symbol)
|
||||
{
|
||||
os << Indent(depth) << "<invalid symbol>\n";
|
||||
return;
|
||||
}
|
||||
PrintSymbolData(*symbol, os, depth);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth)
|
||||
{
|
||||
auto symbol = table_.definition(id);
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
PrintSymbolData(*symbol, os, depth);
|
||||
|
||||
// Example placeholder for children traversal
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolList(std::ostream& os)
|
||||
{
|
||||
for (const auto& sym : table_.all_definitions())
|
||||
PrintSymbol(sym.get().id(), os, 0);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os)
|
||||
{
|
||||
for (const auto& sym : table_.all_definitions())
|
||||
{
|
||||
if (sym.get().kind() == kind)
|
||||
PrintSymbol(sym.get().id(), os, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth)
|
||||
{
|
||||
os << Indent(depth) << "Scope " << id << "\n";
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth)
|
||||
{
|
||||
PrintScope(id, os, depth);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintScopeHierarchy(std::ostream& os)
|
||||
{
|
||||
PrintScopeTree(ScopeId{ 0 }, os, 0);
|
||||
}
|
||||
|
||||
void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os)
|
||||
{
|
||||
auto ids = table_.FindSymbolsByName(name);
|
||||
for (auto id : ids)
|
||||
PrintSymbol(id, os, 0);
|
||||
}
|
||||
|
||||
void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os)
|
||||
{
|
||||
auto id = table_.FindSymbolAt(loc);
|
||||
if (id)
|
||||
PrintSymbol(*id, os, 0);
|
||||
else
|
||||
os << "No symbol at location.\n";
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Indent(int depth) const
|
||||
{
|
||||
return std::string(depth * options_.indent_size, ' ');
|
||||
}
|
||||
|
||||
std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const
|
||||
{
|
||||
return options_.use_color ? Bold(SymbolKindToString(kind)) : SymbolKindToString(kind);
|
||||
}
|
||||
|
||||
std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind) const
|
||||
{
|
||||
return options_.use_color ? Bold(name) : name;
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatLocation(const ast::Location& loc) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[" << loc.start_line << ":" << loc.start_column << " - "
|
||||
<< loc.end_line << ":" << loc.end_column << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatSymbolKind(SymbolKind kind) const
|
||||
{
|
||||
return SymbolKindToString(kind);
|
||||
}
|
||||
|
||||
std::string DebugPrinter::FormatScopeKind(ScopeKind kind) const
|
||||
{
|
||||
return ScopeKindToString(kind);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const
|
||||
{
|
||||
os << std::string(width, ch) << "\n";
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintHeader(const std::string& title, std::ostream& os) const
|
||||
{
|
||||
PrintSeparator(os);
|
||||
os << title << "\n";
|
||||
PrintSeparator(os);
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSubHeader(const std::string& title, std::ostream& os) const
|
||||
{
|
||||
os << title << "\n";
|
||||
PrintSeparator(os, '-', 40);
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Color(const char* color_code) const
|
||||
{
|
||||
return options_.use_color ? std::string(color_code) : std::string();
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Bold(const std::string& text) const
|
||||
{
|
||||
return Color("\033[1m") + text + Color("\033[0m");
|
||||
}
|
||||
|
||||
std::string DebugPrinter::Dim(const std::string& text) const
|
||||
{
|
||||
return Color("\033[2m") + text + Color("\033[0m");
|
||||
}
|
||||
|
||||
void DebugPrinter::PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth)
|
||||
{
|
||||
os << Indent(depth) << ColorizeSymbolName(symbol.name(), symbol.kind())
|
||||
<< " (" << FormatSymbolKind(symbol.kind()) << ")";
|
||||
|
||||
if (options_.show_location)
|
||||
os << " " << FormatLocation(symbol.selection_range());
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
std::string DebugPrinter::GetSymbolIcon(const Symbol& symbol) const
|
||||
{
|
||||
(void)symbol;
|
||||
return {};
|
||||
}
|
||||
|
||||
void Statistics::Print(std::ostream& os, bool use_color) const
|
||||
{
|
||||
auto bold = [&](const std::string& txt) { return use_color ? "\033[1m" + txt + "\033[0m" : txt; };
|
||||
os << bold("Symbols: ") << total_symbols << "\n";
|
||||
os << bold("Scopes : ") << total_scopes << "\n";
|
||||
}
|
||||
|
||||
void Print(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.PrintAll(os);
|
||||
}
|
||||
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.PrintOverview(os);
|
||||
}
|
||||
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.PrintStatistics(os);
|
||||
}
|
||||
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.PrintSymbolTree(SymbolId{ 0 }, os, 0);
|
||||
}
|
||||
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.PrintScopeTree(ScopeId{ 0 }, os, 0);
|
||||
}
|
||||
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table);
|
||||
printer.FindAndPrint(name, os);
|
||||
}
|
||||
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Compact());
|
||||
printer.PrintOverview(os);
|
||||
printer.PrintSymbolList(os);
|
||||
}
|
||||
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os)
|
||||
{
|
||||
DebugPrinter printer(table, PrintOptions::Verbose());
|
||||
printer.PrintAll(os);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
#include "../../src/protocol/protocol.hpp"
|
||||
|
||||
namespace lsp::language::symbol::debug
|
||||
{
|
||||
|
||||
using SymbolKind = protocol::SymbolKind;
|
||||
|
||||
// ==================== 打印选项 ====================
|
||||
|
||||
struct PrintOptions
|
||||
{
|
||||
bool use_color = true; // 使用颜色
|
||||
bool show_location = true; // 显示位置信息
|
||||
bool show_details = true; // 显示详细信息
|
||||
bool show_children = true; // 显示子符号
|
||||
bool compact_mode = false; // 紧凑模式
|
||||
int indent_size = 2; // 缩进大小
|
||||
int max_depth = -1; // 最大深度 (-1 = 无限制)
|
||||
|
||||
static PrintOptions Default();
|
||||
static PrintOptions Compact();
|
||||
static PrintOptions Verbose();
|
||||
static PrintOptions NoColor();
|
||||
};
|
||||
|
||||
// ==================== 统计信息 ====================
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
size_t total_symbols = 0;
|
||||
size_t total_scopes = 0;
|
||||
|
||||
std::unordered_map<SymbolKind, size_t> symbol_counts;
|
||||
std::unordered_map<ScopeKind, size_t> scope_counts;
|
||||
|
||||
void Compute(const SymbolTable& table);
|
||||
void Print(std::ostream& os, bool use_color = true) const;
|
||||
};
|
||||
|
||||
// ==================== 核心打印器 ====================
|
||||
|
||||
class DebugPrinter
|
||||
{
|
||||
public:
|
||||
explicit DebugPrinter(const SymbolTable& table, const PrintOptions& options = PrintOptions::Default());
|
||||
|
||||
// ===== 顶层打印接口 =====
|
||||
void PrintAll(std::ostream& os = std::cout);
|
||||
void PrintOverview(std::ostream& os = std::cout);
|
||||
void PrintStatistics(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 符号打印 =====
|
||||
void PrintSymbol(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolTree(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolList(std::ostream& os = std::cout);
|
||||
void PrintSymbolsByKind(SymbolKind kind, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 作用域打印 =====
|
||||
void PrintScope(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeTree(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeHierarchy(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 搜索和查询 =====
|
||||
void FindAndPrint(const std::string& name, std::ostream& os = std::cout);
|
||||
void FindAtLocation(const ast::Location& loc, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 选项管理 =====
|
||||
void SetOptions(const PrintOptions& options) { options_ = options; }
|
||||
const PrintOptions& GetOptions() const { return options_; }
|
||||
|
||||
private:
|
||||
const SymbolTable& table_;
|
||||
PrintOptions options_;
|
||||
Statistics stats_;
|
||||
|
||||
// ===== 辅助方法 =====
|
||||
std::string Indent(int depth) const;
|
||||
std::string ColorizeSymbolKind(SymbolKind kind) const;
|
||||
std::string ColorizeSymbolName(const std::string& name, SymbolKind kind) const;
|
||||
std::string FormatLocation(const ast::Location& loc) const;
|
||||
std::string FormatSymbolKind(SymbolKind kind) const;
|
||||
std::string FormatScopeKind(ScopeKind kind) const;
|
||||
std::string SymbolIcon(SymbolKind kind) const;
|
||||
|
||||
void PrintSeparator(std::ostream& os, char ch = '=', int width = 80) const;
|
||||
void PrintHeader(const std::string& title, std::ostream& os) const;
|
||||
void PrintSubHeader(const std::string& title, std::ostream& os) const;
|
||||
|
||||
std::string Color(const char* color_code) const;
|
||||
std::string Bold(const std::string& text) const;
|
||||
std::string Dim(const std::string& text) const;
|
||||
|
||||
void PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth);
|
||||
void PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap<SymbolId, SymbolId>& children, std::ostream& os, int depth, int current_depth);
|
||||
std::string GetSymbolIcon(const Symbol& symbol) const;
|
||||
};
|
||||
|
||||
// ==================== 快速打印函数 ====================
|
||||
|
||||
void Print(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os = std::cout);
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
} // namespace lsp::language::symbol::debug
|
||||
@@ -1,26 +1,15 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
module;
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
export module lsp.test.symbol.main;
|
||||
|
||||
import std;
|
||||
import tree_sitter;
|
||||
import lsp.language.ast;
|
||||
import lsp.language.symbol;
|
||||
import lsp.test.symbol.debug_printer;
|
||||
|
||||
extern "C" const TSLanguage* tree_sitter_tsf(void);
|
||||
|
||||
#include "../../src/language/ast/deserializer.hpp"
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
#include "./debug_printer.hpp"
|
||||
|
||||
using namespace lsp::language;
|
||||
|
||||
// ==================== 文件读取 ====================
|
||||
Reference in New Issue
Block a user