From 2c4783c90430f43250573ffcacaaadbfe6d98705 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 14 Jan 2018 14:24:47 -0800 Subject: [PATCH] Rename Get{Buffer,Index}LineFrom{Index,Buffer}Line in preparation for column alignment. --- src/messages/text_document_document_link.cc | 2 +- src/query_utils.cc | 16 ++++++----- src/working_files.cc | 31 ++++++++++++++++++--- src/working_files.h | 12 ++++---- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/messages/text_document_document_link.cc b/src/messages/text_document_document_link.cc index 341d8d85..cb51a159 100644 --- a/src/messages/text_document_document_link.cc +++ b/src/messages/text_document_document_link.cc @@ -62,7 +62,7 @@ struct TextDocumentDocumentLinkHandler } for (const IndexInclude& include : file->def->includes) { optional buffer_line = - working_file->GetBufferLineFromIndexLine(include.line); + working_file->GetBufferPosFromIndexPos(include.line, nullptr); if (!buffer_line) continue; diff --git a/src/query_utils.cc b/src/query_utils.cc index 8679b80c..90d62b74 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -318,11 +318,12 @@ optional GetLsPosition(WorkingFile* working_file, if (!working_file) return lsPosition(position.line, position.column); - optional start = working_file->GetBufferLineFromIndexLine(position.line); + int column = position.column; + optional start = working_file->GetBufferPosFromIndexPos(position.line, &column); if (!start) return nullopt; - return lsPosition(*start, position.column); + return lsPosition(*start, column); } optional GetLsRange(WorkingFile* working_file, const Range& location) { @@ -332,10 +333,11 @@ optional GetLsRange(WorkingFile* working_file, const Range& location) { lsPosition(location.end.line, location.end.column)); } + int start_column = location.start.column, end_column = location.end.column; optional start = - working_file->GetBufferLineFromIndexLine(location.start.line); + working_file->GetBufferPosFromIndexPos(location.start.line, &start_column); optional end = - working_file->GetBufferLineFromIndexLine(location.end.line); + working_file->GetBufferPosFromIndexPos(location.end.line, &end_column); if (!start || !end) return nullopt; @@ -348,8 +350,8 @@ optional GetLsRange(WorkingFile* working_file, const Range& location) { if (*end < *start) *end = *start + (location.end.line - location.start.line); - return lsRange(lsPosition(*start, location.start.column), - lsPosition(*end, location.end.column)); + return lsRange(lsPosition(*start, start_column), + lsPosition(*end, end_column)); } lsDocumentUri GetLsDocumentUri(QueryDatabase* db, @@ -482,7 +484,7 @@ std::vector FindSymbolsAtLocation(WorkingFile* working_file, int target_column = position.character; if (working_file) { optional index_line = - working_file->GetIndexLineFromBufferLine(target_line); + working_file->GetIndexPosFromBufferPos(target_line, &target_column); if (index_line) target_line = *index_line; } diff --git a/src/working_files.cc b/src/working_files.cc index 32e4ea7c..99de089d 100644 --- a/src/working_files.cc +++ b/src/working_files.cc @@ -8,6 +8,7 @@ #include #include +#include namespace { @@ -68,12 +69,34 @@ int MyersDiff(const std::string& a, const std::string& b, int threshold) { return MyersDiff(a.data(), a.size(), b.data(), b.size(), threshold); } +// Computes Levenshtein edit distance with O(N*M) Needleman-Wunsch algorithm +// and returns a distance vector where d[i] = cost of aligning a to b[0,i). +// +// Myers' diff algorithm is used to find best matching line while this one is +// used to align a single column because Myers' needs some twiddling to return +// distance vector. +std::vector LevenshteinDistance(std::string a, std::string b) { + std::vector d(b.size() + 1); + std::iota(d.begin(), d.end(), 0); + for (int i = 0; i < (int)a.size(); i++) { + int ul = d[0]; + d[0] = i + 1; + for (int j = 0; j < (int)b.size(); j++) { + int t = d[j + 1]; + d[j + 1] = a[i] == b[j] ? ul : std::min(ul, std::min(d[j], d[j + 1])) + 1; + ul = t; + } + } + return d; +} + // Find matching buffer line of index_lines[line]. // By symmetry, this can also be used to find matching index line of a buffer // line. optional FindMatchingLine(const std::vector& index_lines, const std::vector& index_to_buffer, int line, + int* column, const std::vector& buffer_lines) { // If this is a confident mapping, returns. if (index_to_buffer[line] >= 0) @@ -225,7 +248,7 @@ void WorkingFile::ComputeLineMapping() { buffer_to_index[index_to_buffer[i]] = i; } -optional WorkingFile::GetBufferLineFromIndexLine(int line) { +optional WorkingFile::GetBufferPosFromIndexPos(int line, int* column) { // The implementation is simple but works pretty well for most cases. We // lookup the line contents in the indexed file contents, and try to find the // most similar line in the current buffer file. @@ -248,10 +271,10 @@ optional WorkingFile::GetBufferLineFromIndexLine(int line) { if (index_to_buffer.empty()) ComputeLineMapping(); - return FindMatchingLine(index_lines, index_to_buffer, line, buffer_lines); + return FindMatchingLine(index_lines, index_to_buffer, line, column, buffer_lines); } -optional WorkingFile::GetIndexLineFromBufferLine(int line) { +optional WorkingFile::GetIndexPosFromBufferPos(int line, int* column) { // See GetBufferLineFromIndexLine for additional comments. // Note: |index_line| and |buffer_line| are 1-based. @@ -265,7 +288,7 @@ optional WorkingFile::GetIndexLineFromBufferLine(int line) { if (buffer_to_index.empty()) ComputeLineMapping(); - return FindMatchingLine(buffer_lines, buffer_to_index, line, index_lines); + return FindMatchingLine(buffer_lines, buffer_to_index, line, column, index_lines); } std::string WorkingFile::FindClosestCallNameInBuffer( diff --git a/src/working_files.h b/src/working_files.h index c93712b3..ab115db0 100644 --- a/src/working_files.h +++ b/src/working_files.h @@ -38,12 +38,12 @@ struct WorkingFile { // This should be called whenever |buffer_content| has changed. void OnBufferContentUpdated(); - // Find the buffer-line which should be shown for |indexed_line|. This - // accepts and returns 1-based lines. - optional GetBufferLineFromIndexLine(int indexed_line); - // Find the indexed-line which should be shown for |buffer_line|. This - // accepts and returns 1-based lines. - optional GetIndexLineFromBufferLine(int buffer_line); + // Finds the buffer line number which maps to index line number |line|. + // Also resolves |column| if not NULL. + optional GetBufferPosFromIndexPos(int line, int* column); + // Finds the index line number which maps to buffer line number |line|. + // Also resolves |column| if not NULL. + optional GetIndexPosFromBufferPos(int line, int* column); // TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into // lex_utils.h/cc