tsl-devkit/lsp-server/test/test_symbol/debug_printer.cppm

475 lines
14 KiB
C++

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);
}
}