#include #include "./document.hpp" namespace lsp::services { // ===== Document 实现 ===== Document::Document(const protocol::TextDocumentItem& item) : item_(item), last_modified_time_(std::chrono::system_clock::now()) { UpdateInternalState(); spdlog::trace("Created document: {} (version {}, {} bytes)", item_.uri, item_.version, item_.text.length()); } void Document::SetContent(int32_t newVersion, const std::string& newText) { item_.version = newVersion; item_.text = newText; is_dirty_ = true; last_modified_time_ = std::chrono::system_clock::now(); UpdateInternalState(); spdlog::trace("Document {} updated to version {} ({} bytes)", item_.uri, item_.version, item_.text.length()); } void Document::ApplyContentChange(protocol::integer version, const std::vector& changes) { // 应用所有变更 for (const auto& change : changes) { ApplyContentChange(change); } item_.version = version; is_dirty_ = true; last_modified_time_ = std::chrono::system_clock::now(); UpdateInternalState(); spdlog::trace("Document {} updated to version {} with {} changes", item_.uri, item_.version, changes.size()); } void Document::ApplyContentChange(const protocol::TextDocumentContentChangeEvent& change) { // 增量更新 size_t startOffset = PositionToOffset(change.range.start); size_t endOffset = PositionToOffset(change.range.end); // 替换指定范围 item_.text = item_.text.substr(0, startOffset) + change.text + item_.text.substr(endOffset); } size_t Document::PositionToOffset(const protocol::Position& position) const { if (position.line >= lines_.size()) { return item_.text.length(); } size_t offset = line_offsets_[position.line]; // 根据编码计算字符偏移 if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8) { // 直接使用字节偏移 offset += std::min(static_cast(position.character), lines_[position.line].length()); } else { // UTF-16 或 UTF-32 offset += CharacterToByteOffset(lines_[position.line], position.character); } return offset; } protocol::Position Document::OffsetToPosition(size_t offset) const { protocol::Position pos; pos.line = 0; pos.character = 0; // 二分查找行号 auto it = std::upper_bound(line_offsets_.begin(), line_offsets_.end(), offset); if (it != line_offsets_.begin()) { --it; pos.line = static_cast(std::distance(line_offsets_.begin(), it)); size_t lineOffset = *it; size_t byteOffset = offset - lineOffset; // 根据编码计算字符位置 if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8) { pos.character = static_cast(byteOffset); } else { pos.character = ByteOffsetToCharacter(lines_[pos.line], byteOffset); } } return pos; } std::string Document::GetTextInRange(const protocol::Range& range) const { size_t start = PositionToOffset(range.start); size_t end = PositionToOffset(range.end); if (start >= item_.text.length()) { return ""; } end = std::min(end, item_.text.length()); return item_.text.substr(start, end - start); } std::optional Document::GetCharAt(const protocol::Position& position) const { if (position.line >= lines_.size()) { return std::nullopt; } const std::string& line = lines_[position.line]; size_t byteOffset = CharacterToByteOffset(line, position.character); if (byteOffset >= line.length()) { return std::nullopt; } return line[byteOffset]; } std::string Document::GetLine(size_t lineNumber) const { if (lineNumber < lines_.size()) { return lines_[lineNumber]; } return ""; } std::string Document::GetLineAt(const protocol::Position& position) const { return GetLine(position.line); } std::string Document::GetWordAt(const protocol::Position& position) const { if (position.line >= lines_.size()) { return ""; } const std::string& line = lines_[position.line]; size_t bytePos = CharacterToByteOffset(line, position.character); // 找到单词边界 size_t start = bytePos; while (start > 0 && IsWordChar(line[start - 1])) { --start; } size_t end = bytePos; while (end < line.length() && IsWordChar(line[end])) { ++end; } return line.substr(start, end - start); } protocol::Range Document::GetWordRangeAt(const protocol::Position& position) const { if (position.line >= lines_.size()) { return protocol::Range{ position, position }; } const std::string& line = lines_[position.line]; size_t bytePos = CharacterToByteOffset(line, position.character); // 找到单词边界 size_t start = bytePos; while (start > 0 && IsWordChar(line[start - 1])) { --start; } size_t end = bytePos; while (end < line.length() && IsWordChar(line[end])) { ++end; } protocol::Range range; range.start.line = position.line; range.start.character = ByteOffsetToCharacter(line, start); range.end.line = position.line; range.end.character = ByteOffsetToCharacter(line, end); return range; } void Document::UpdateInternalState() { UpdateLines(); UpdateLineOffsets(); } void Document::UpdateLines() { lines_.clear(); size_t start = 0; for (size_t i = 0; i < item_.text.length(); ++i) { if (item_.text[i] == '\n') { lines_.push_back(item_.text.substr(start, i - start)); start = i + 1; } else if (item_.text[i] == '\r') { if (i + 1 < item_.text.length() && item_.text[i + 1] == '\n') { lines_.push_back(item_.text.substr(start, i - start)); start = i + 2; ++i; // Skip \n } else { lines_.push_back(item_.text.substr(start, i - start)); start = i + 1; } } } // 添加最后一行 if (start <= item_.text.length()) { lines_.push_back(item_.text.substr(start)); } } void Document::UpdateLineOffsets() { line_offsets_.clear(); line_offsets_.reserve(lines_.size() + 1); size_t offset = 0; line_offsets_.push_back(0); for (size_t i = 0; i < item_.text.length(); ++i) { if (item_.text[i] == '\n') { line_offsets_.push_back(i + 1); } else if (item_.text[i] == '\r') { if (i + 1 < item_.text.length() && item_.text[i + 1] == '\n') { line_offsets_.push_back(i + 2); ++i; } else { line_offsets_.push_back(i + 1); } } } } bool Document::IsWordChar(char c) const { return std::isalnum(static_cast(c)) || c == '_' || c == '$'; } size_t Document::CharacterToByteOffset(const std::string& line, int32_t character) const { if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8) { return std::min(static_cast(character), line.length()); } // UTF-16 编码:需要正确计算 size_t byteOffset = 0; int32_t charCount = 0; while (byteOffset < line.length() && charCount < character) { unsigned char c = line[byteOffset]; if (encoding_ == protocol::PositionEncodingKindLiterals::UTF16) { // UTF-16: 计算代码单元 if ((c & 0x80) == 0) { // ASCII byteOffset += 1; charCount += 1; } else if ((c & 0xE0) == 0xC0) { // 2字节UTF-8 -> 1个UTF-16单元 byteOffset += 2; charCount += 1; } else if ((c & 0xF0) == 0xE0) { // 3字节UTF-8 -> 1个UTF-16单元 byteOffset += 3; charCount += 1; } else if ((c & 0xF8) == 0xF0) { // 4字节UTF-8 -> 2个UTF-16单元(代理对) byteOffset += 4; charCount += 2; } else { byteOffset += 1; // 错误情况 } } else // UTF32 { // UTF-32: 每个Unicode代码点算一个 if ((c & 0x80) == 0) { byteOffset += 1; } else if ((c & 0xE0) == 0xC0) { byteOffset += 2; } else if ((c & 0xF0) == 0xE0) { byteOffset += 3; } else if ((c & 0xF8) == 0xF0) { byteOffset += 4; } else { byteOffset += 1; } charCount += 1; } } return byteOffset; } int32_t Document::ByteOffsetToCharacter(const std::string& line, size_t byteOffset) const { if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8) { return static_cast(byteOffset); } int32_t charCount = 0; size_t pos = 0; while (pos < byteOffset && pos < line.length()) { unsigned char c = line[pos]; if (encoding_ == protocol::PositionEncodingKindLiterals::UTF16) { if ((c & 0x80) == 0) { pos += 1; charCount += 1; } else if ((c & 0xE0) == 0xC0) { pos += 2; charCount += 1; } else if ((c & 0xF0) == 0xE0) { pos += 3; charCount += 1; } else if ((c & 0xF8) == 0xF0) { pos += 4; charCount += 2; // 代理对 } else { pos += 1; charCount += 1; } } else // UTF32 { if ((c & 0x80) == 0) { pos += 1; } else if ((c & 0xE0) == 0xC0) { pos += 2; } else if ((c & 0xF0) == 0xE0) { pos += 3; } else if ((c & 0xF8) == 0xF0) { pos += 4; } else { pos += 1; } charCount += 1; } } return charCount; } // ===== DocumentManager 实现 ===== void DocumentManager::DidOpenTextDocument(const protocol::DidOpenTextDocumentParams& params) { std::unique_lock lock(mutex_); // 检查文档大小 if (config_.max_document_size > 0 && params.textDocument.text.length() > config_.max_document_size) { spdlog::error("Document {} exceeds maximum size ({} > {})", params.textDocument.uri, params.textDocument.text.length(), config_.max_document_size); return; } // 创建新文档 auto doc = std::make_shared(params.textDocument); doc->SetEncoding(config_.default_encoding); documents_[params.textDocument.uri] = doc; spdlog::info("Opened document: {} (version {}, {} bytes, language: {})", params.textDocument.uri, params.textDocument.version, params.textDocument.text.length(), params.textDocument.languageId); } void DocumentManager::DidChangeTextDocument(const protocol::DidChangeTextDocumentParams& params) { std::unique_lock lock(mutex_); auto it = documents_.find(params.textDocument.uri); if (it == documents_.end()) { spdlog::error("Attempt to change non-existent document: {}", params.textDocument.uri); return; } auto& doc = it->second; // 版本检查 if (params.textDocument.version) { protocol::integer expectedVersion = params.textDocument.version; if (expectedVersion <= doc->GetVersion()) { spdlog::warn("Ignoring stale change for {}: version {} <= current {}", params.textDocument.uri, expectedVersion, doc->GetVersion()); return; } } // 应用变更 if (params.contentChanges.empty()) { spdlog::warn("Empty content changes for document: {}", params.textDocument.uri); return; } // 检查是全文还是增量 if (params.contentChanges.size() == 1) { // 全文更新 // doc->SetContent(params.textDocument.version(doc->GetVersion() + 1), params.contentChanges[0].text); } else { // 增量更新 // doc->ApplyContentChanges( params.textDocument.version(doc->GetVersion() + 1), params.contentChanges); } spdlog::debug("Changed document: {} to version {} ({} changes)", params.textDocument.uri, doc->GetVersion(), params.contentChanges.size()); } void DocumentManager::DidCloseTextDocument(const protocol::DidCloseTextDocumentParams& params) { std::unique_lock lock(mutex_); auto it = documents_.find(params.textDocument.uri); if (it == documents_.end()) { spdlog::warn("Attempt to close non-existent document: {}", params.textDocument.uri); return; } documents_.erase(it); spdlog::info("Closed document: {}", params.textDocument.uri); } void DocumentManager::DidSaveTextDocument(const protocol::DidSaveTextDocumentParams& params) { std::shared_lock lock(mutex_); auto it = documents_.find(params.textDocument.uri); if (it == documents_.end()) { spdlog::warn("Attempt to save non-existent document: {}", params.textDocument.uri); return; } it->second->SetDirty(false); // 如果保存通知包含文本,可以验证同步状态 if (params.text.has_value()) { if (params.text.value() != it->second->GetText()) { spdlog::error("Document content mismatch on save for: {}", params.textDocument.uri); } } spdlog::info("Saved document: {}", params.textDocument.uri); } std::shared_ptr DocumentManager::GetDocument(const std::string& uri) const { std::shared_lock lock(mutex_); auto it = documents_.find(uri); if (it != documents_.end()) { return it->second; } return nullptr; } std::vector DocumentManager::GetAllUris() const { std::shared_lock lock(mutex_); std::vector uris; uris.reserve(documents_.size()); for (const auto& [uri, doc] : documents_) { uris.push_back(uri); } return uris; } std::vector> DocumentManager::GetAllDocuments() const { std::shared_lock lock(mutex_); std::vector> docs; docs.reserve(documents_.size()); for (const auto& [uri, doc] : documents_) { docs.push_back(doc); } return docs; } std::vector> DocumentManager::GetDocumentsByLanguage( const std::string& languageId) const { std::shared_lock lock(mutex_); std::vector> docs; for (const auto& [uri, doc] : documents_) { if (doc->GetLanguageId() == languageId) { docs.push_back(doc); } } return docs; } bool DocumentManager::HasDocument(const std::string& uri) const { std::shared_lock lock(mutex_); return documents_.find(uri) != documents_.end(); } size_t DocumentManager::GetDocumentCount() const { std::shared_lock lock(mutex_); return documents_.size(); } std::vector DocumentManager::GetDirtyDocuments() const { std::shared_lock lock(mutex_); std::vector dirtyUris; for (const auto& [uri, doc] : documents_) { if (doc->IsDirty()) { dirtyUris.push_back(uri); } } return dirtyUris; } std::string DocumentManager::ResolveUri(const std::string& uri) const { // 如果已经是绝对URI,直接返回 if (utils::IsFileUri(uri)) { return uri; } // 尝试相对于工作区文件夹解析 for (const auto& folder : workspace_folders_) { std::string folderPath = utils::UriToPath(folder.uri); std::string resolvedPath = folderPath + "/" + uri; // 检查文件是否存在(这里简化处理) return utils::PathToUri(resolvedPath); } return uri; } // ===== 工具函数实现 ===== namespace utils { std::string NormalizeUri(const std::string& uri) { std::string normalized = uri; // 确保使用正斜杠 std::replace(normalized.begin(), normalized.end(), '\\', '/'); // 移除重复的斜杠 auto newEnd = std::unique(normalized.begin(), normalized.end(), [](char a, char b) { return a == '/' && b == '/'; }); normalized.erase(newEnd, normalized.end()); return normalized; } std::string UriToPath(const std::string& uri) { if (uri.substr(0, 7) == "file://") { std::string path = uri.substr(7); // Windows路径处理 #ifdef _WIN32 if (path.length() >= 3 && path[0] == '/' && std::isalpha(path[1]) && path[2] == ':') { path = path.substr(1); } #endif return path; } return uri; } std::string PathToUri(const std::string& path) { std::string uri = "file://"; #ifdef _WIN32 // Windows路径 if (path.length() >= 2 && std::isalpha(path[0]) && path[1] == ':') { uri += "/"; } #endif uri += path; return NormalizeUri(uri); } bool IsFileUri(const std::string& uri) { return uri.substr(0, 7) == "file://"; } protocol::TextEdit CreateReplace(const protocol::Range& range, const std::string& newText) { protocol::TextEdit edit; edit.range = range; edit.newText = newText; return edit; } protocol::TextEdit CreateInsert(const protocol::Position& position, const std::string& text) { return CreateReplace(protocol::Range{ position, position }, text); } protocol::TextEdit CreateDelete(const protocol::Range& range) { return CreateReplace(range, ""); } bool IsPositionInRange(const protocol::Position& position, const protocol::Range& range) { if (position.line < range.start.line || position.line > range.end.line) { return false; } if (position.line == range.start.line && position.character < range.start.character) { return false; } if (position.line == range.end.line && position.character >= range.end.character) { return false; } return true; } bool IsRangeOverlapping(const protocol::Range& a, const protocol::Range& b) { return !(a.end.line < b.start.line || (a.end.line == b.start.line && a.end.character <= b.start.character) || b.end.line < a.start.line || (b.end.line == a.start.line && b.end.character <= a.start.character)); } protocol::Range ExtendRange(const protocol::Range& range, int32_t lines) { protocol::Range extended = range; extended.start.line = std::max(static_cast(0), static_cast(extended.start.line - lines)); extended.end.line += lines; return extended; } std::string ApplyTextEdits(const std::string& text, const std::vector& edits) { if (edits.empty()) { return text; } // 排序编辑(从后向前,避免偏移问题) std::vector sortedEdits = edits; std::sort(sortedEdits.begin(), sortedEdits.end(), [](const protocol::TextEdit& a, const protocol::TextEdit& b) { if (a.range.start.line != b.range.start.line) { return a.range.start.line > b.range.start.line; } return a.range.start.character > b.range.start.character; }); // 创建临时文档来应用编辑 protocol::TextDocumentItem tempItem; tempItem.uri = "temp://"; tempItem.languageId = ""; tempItem.version = 0; tempItem.text = text; Document tempDoc(tempItem); std::string result = text; for (const auto& edit : sortedEdits) { size_t start = tempDoc.PositionToOffset(edit.range.start); size_t end = tempDoc.PositionToOffset(edit.range.end); result = result.substr(0, start) + edit.newText + result.substr(end); // 更新临时文档 tempDoc.SetContent(0, result); } return result; } } }