From 07feb1c52cf364c6f3c9bd99a891d09da8c25c3c Mon Sep 17 00:00:00 2001 From: csh Date: Thu, 3 Jul 2025 18:51:05 +0800 Subject: [PATCH] commandline params --- lsp-server/src/main.cpp | 135 +++++++++----------------- lsp-server/src/utils/args_parser.cpp | 140 +++++++++++++++++++++++++++ lsp-server/src/utils/args_parser.hpp | 23 +++++ 3 files changed, 208 insertions(+), 90 deletions(-) create mode 100644 lsp-server/src/utils/args_parser.cpp create mode 100644 lsp-server/src/utils/args_parser.hpp diff --git a/lsp-server/src/main.cpp b/lsp-server/src/main.cpp index 25ae73f..52ea267 100644 --- a/lsp-server/src/main.cpp +++ b/lsp-server/src/main.cpp @@ -1,90 +1,45 @@ -#include -#include -#include -#include -#include -#include -#include -#include "./lsp/server.hpp" - -void ParseArgs(int argc, char* argv[]) -{ - std::vector sinks; - - bool use_stderr = false; - std::string log_file; - spdlog::level::level_enum log_level = spdlog::level::info; - - for (int i = 1; i < argc; ++i) - { - std::string arg = argv[i]; - if (arg == "--log=trace") - log_level = spdlog::level::trace; - else if (arg == "--log=debug") - log_level = spdlog::level::debug; - else if (arg == "--log=info") - log_level = spdlog::level::info; - else if (arg == "--log=warn") - log_level = spdlog::level::warn; - else if (arg == "--log=error") - log_level = spdlog::level::err; - else if (arg == "--log=off") - log_level = spdlog::level::off; - else if (arg.find("--log-file=") == 0) - log_file = arg.substr(11); // 跳过 "--log-file=" - else if (arg == "--log-stderr") - use_stderr = true; - } - - sinks.clear(); - - if (use_stderr) - sinks.push_back(std::make_shared()); - // 如果指定了日志文件,添加文件 sink - if (!log_file.empty()) - { - try - { - sinks.push_back(std::make_shared(log_file, true)); - } - catch (const std::exception& e) - { - std::cerr << "[TSL-LSP] Failed to create log file: " << e.what() << std::endl; - } - } - - std::shared_ptr logger = std::make_shared("tsl_lsp", sinks.begin(), sinks.end()); - logger->set_level(log_level); - logger->set_pattern("[%Y-%m-%d %H:%M:%S] [%^%l%$] %v"); - - // 设置为默认日志器 - spdlog::set_default_logger(logger); - spdlog::flush_on(spdlog::level::warn); -} - -int main(int argc, char* argv[]) -{ - ParseArgs(argc, argv); - try - { - spdlog::info("TSL-LSP server starting..."); - lsp::LspServer server; - server.Run(); - } - catch (const std::exception& e) - { - std::cerr << "[TSL-LSP] Server fatal error: " << e.what() << std::endl; - spdlog::error("Server fatal error: ", e.what()); - return 1; - } - catch (...) - { - std::cerr << "[TSL-LSP] Server unknown fatal error" << std::endl; - spdlog::error("Server unknown fatal error"); - return 1; - } - - spdlog::info("TSL-LSP server stopped normally"); - spdlog::shutdown(); - return 0; -} +#include +#include +#include +#include +#include +#include +#include +#include "./lsp/server.hpp" +#include "./utils/args_parser.hpp" + +int main(int argc, char* argv[]) +{ + lsp::utils::ServerConfig config = lsp::utils::ArgsParser::Parse(argc, argv); + + if (config.show_help) + { + lsp::utils::ArgsParser::PrintHelp(argv[0]); + return 0; + } + + lsp::utils::ArgsParser::SetupLogger(config); + + try + { + spdlog::info("TSL-LSP server starting..."); + lsp::LspServer server(config.thread_count); + server.Run(); + } + catch (const std::exception& e) + { + std::cerr << "[TSL-LSP] Server fatal error: " << e.what() << std::endl; + spdlog::error("Server fatal error: ", e.what()); + return 1; + } + catch (...) + { + std::cerr << "[TSL-LSP] Server unknown fatal error" << std::endl; + spdlog::error("Server unknown fatal error"); + return 1; + } + + spdlog::info("TSL-LSP server stopped normally"); + spdlog::shutdown(); + return 0; +} diff --git a/lsp-server/src/utils/args_parser.cpp b/lsp-server/src/utils/args_parser.cpp new file mode 100644 index 0000000..8014fbf --- /dev/null +++ b/lsp-server/src/utils/args_parser.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include "./args_parser.hpp" + +namespace lsp::utils +{ + ServerConfig ArgsParser::Parse(int argc, char* argv[]) + { + ServerConfig config; + + for (int i = 1; i < argc; ++i) + { + std::string arg = argv[i]; + + if (arg == "--help") + { + config.show_help = true; + return config; + } + + if (arg == "--log=trace") + config.log_level = spdlog::level::trace; + else if (arg == "--log=debug") + config.log_level = spdlog::level::debug; + else if (arg == "--log=info") + config.log_level = spdlog::level::info; + else if (arg == "--log=warn") + config.log_level = spdlog::level::warn; + else if (arg == "--log=error") + config.log_level = spdlog::level::err; + else if (arg == "--log=off") + config.log_level = spdlog::level::off; + else if (arg.find("--log-file=") == 0) + config.log_file = arg.substr(11); + else if (arg == "--log-stderr") + config.use_stderr = true; + else if (arg.find("--threads=") == 0) + { + std::string count_str = arg.substr(10); + try + { + size_t count = std::stoul(count_str); + if (count == 0 || count > 32) + { + std::cerr << "[TSL-LSP] Error: Thread count must be between 1 and 32" << std::endl; + std::exit(1); + } + config.thread_count = count; + } + catch (const std::exception&) + { + std::cerr << "[TSL-LSP] Error: Invalid thread count: " << count_str << std::endl; + std::exit(1); + } + } + else + { + std::cerr << "[TSL-LSP] Error: Unknown argument: " << arg << std::endl; + std::cerr << "Use --help for usage information" << std::endl; + } + } + + return config; + } + + void ArgsParser::SetupLogger(const ServerConfig& config) + { + std::vector sinks; + + if (config.use_stderr) + sinks.push_back(std::make_shared()); + + if (!config.log_file.empty()) + { + try + { + sinks.push_back(std::make_shared(config.log_file, true)); + } + catch (const std::exception& e) + { + std::cerr << "[TSL-LSP] Failed to create log file: " << e.what() << std::endl; + } + } + + auto logger = std::make_shared("tsl_lsp", sinks.begin(), sinks.end()); + logger->set_level(config.log_level); + logger->set_pattern("[%Y-%m-%d %H:%M:%S] [%^%l%$] %v"); + + spdlog::set_default_logger(logger); + spdlog::flush_on(spdlog::level::warn); + } + + void ArgsParser::PrintHelp(const std::string& program_name) + { + // 获取硬件线程数 + size_t hardware_threads = std::thread::hardware_concurrency(); + if (hardware_threads == 0) + hardware_threads = 0; // 表示无法检测 + + std::cout << "TSL Language Server Protocol (LSP) Server\n" + << "\n" + << "Usage: " << program_name << " [options]\n" + << "\n" + << "Options:\n" + << " --help, -h Show this help message and exit\n" + << "\n" + << "Logging options:\n" + << " --log=LEVEL Set log level (trace, debug, info, warn, error, off)\n" + << " Default: info\n" + << " --log-file=PATH Write logs to file at PATH\n" + << " --log-stderr Output logs to stderr\n" + << "\n" + << "Performance options:\n" + << " --threads=N Set number of worker threads (1-32)\n" + << " Default: 4\n"; + + // 显示硬件信息 + if (hardware_threads > 0) + std::cout << " Hardware threads available: " << hardware_threads << "\n"; + else + std::cout << " Hardware threads: unable to detect\n"; + + std::cout << "\n" + << "Examples:\n" + << " # Run with debug logging to stderr\n" + << " " << program_name << " --log=debug --log-stderr\n" + << "\n" + << " # Run with 8 worker threads and log to file\n" + << " " << program_name << " --threads=8 --log-file=server.log\n" + << "\n" + << " # Run with maximum hardware threads\n"; + + if (hardware_threads > 0) + std::cout << " " << program_name << " --threads=" << hardware_threads << "\n"; + else + std::cout << " " << program_name << " --threads=16 # adjust based on your CPU\n"; + } + +} diff --git a/lsp-server/src/utils/args_parser.hpp b/lsp-server/src/utils/args_parser.hpp new file mode 100644 index 0000000..dd8a4c1 --- /dev/null +++ b/lsp-server/src/utils/args_parser.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include + +namespace lsp::utils +{ + struct ServerConfig + { + bool use_stderr = false; + std::string log_file; + spdlog::level::level_enum log_level = spdlog::level::info; + size_t thread_count = 4; + bool show_help = false; + }; + + class ArgsParser + { + public: + static ServerConfig Parse(int argc, char* argv[]); + static void SetupLogger(const ServerConfig& config); + static void PrintHelp(const std::string& program_name); + }; +}