mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
Better :: lexing and fix ci
This commit is contained in:
parent
61b5ef4fa0
commit
d4c49730fd
106
src/lex_utils.cc
106
src/lex_utils.cc
@ -3,6 +3,7 @@
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent
|
||||
// text documents.
|
||||
@ -197,35 +198,31 @@ void LexFunctionDeclaration(const std::string& buffer_content,
|
||||
*insert_text = result;
|
||||
}
|
||||
|
||||
std::string LexWordAroundPos(lsPosition position, const std::string& content) {
|
||||
int index = GetOffsetForPosition(position, content);
|
||||
std::string_view LexIdentifierAroundPos(lsPosition position,
|
||||
std::string_view content) {
|
||||
int start = GetOffsetForPosition(position, content);
|
||||
int end = start + 1;
|
||||
char c;
|
||||
|
||||
int start = index;
|
||||
int end = index + 1;
|
||||
|
||||
// We search for : before the cursor but not after to get the qualifier.
|
||||
while (start > 0) {
|
||||
char c = content[start - 1];
|
||||
if (isalnum(c) || c == '_' || c == ':') {
|
||||
--start;
|
||||
} else {
|
||||
// We search for :: before the cursor but not after to get the qualifier.
|
||||
for (; start > 0; start--) {
|
||||
c = content[start - 1];
|
||||
if (isalnum(c) || c == '_')
|
||||
;
|
||||
else if (c == ':' && start > 1 && content[start - 2] == ':')
|
||||
start--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (end < (int)content.size()) {
|
||||
char c = content[end];
|
||||
if (isalnum(c) || c == '_') {
|
||||
++end;
|
||||
} else {
|
||||
for (; end < (int)content.size(); end++)
|
||||
if (c = content[end], !(isalnum(c) || c == '_'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return content.substr(start, end - start);
|
||||
}
|
||||
|
||||
bool SubsequenceMatch(std::string_view search, std::string_view content) {
|
||||
bool SubsequenceMatchIgnoreCase(std::string_view search, std::string_view content) {
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < search.size(); i++) {
|
||||
char search_char = tolower(search[i]);
|
||||
@ -280,33 +277,29 @@ TEST_SUITE("Offset") {
|
||||
|
||||
TEST_SUITE("Substring") {
|
||||
TEST_CASE("match") {
|
||||
// Sanity.
|
||||
REQUIRE(SubsequenceMatch("a", "aa"));
|
||||
REQUIRE(SubsequenceMatch("aa", "aa"));
|
||||
|
||||
// Empty string matches anything.
|
||||
REQUIRE(SubsequenceMatch("", ""));
|
||||
REQUIRE(SubsequenceMatch("", "aa"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("", ""));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("", "aa"));
|
||||
|
||||
// Match in start/middle/end.
|
||||
REQUIRE(SubsequenceMatch("a", "abbbb"));
|
||||
REQUIRE(SubsequenceMatch("a", "bbabb"));
|
||||
REQUIRE(SubsequenceMatch("a", "bbbba"));
|
||||
REQUIRE(SubsequenceMatch("aa", "aabbb"));
|
||||
REQUIRE(SubsequenceMatch("aa", "bbaab"));
|
||||
REQUIRE(SubsequenceMatch("aa", "bbbaa"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("a", "abbbb"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("a", "bbabb"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("a", "bbbba"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "aabbb"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "bbaab"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "bbbaa"));
|
||||
|
||||
// Capitalization.
|
||||
REQUIRE(SubsequenceMatch("aa", "aA"));
|
||||
REQUIRE(SubsequenceMatch("aa", "Aa"));
|
||||
REQUIRE(SubsequenceMatch("aa", "AA"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "aA"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "Aa"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("aa", "AA"));
|
||||
|
||||
// Token skipping.
|
||||
REQUIRE(SubsequenceMatch("ad", "abcd"));
|
||||
REQUIRE(SubsequenceMatch("ad", "ABCD"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("ad", "abcd"));
|
||||
REQUIRE(SubsequenceMatchIgnoreCase("ad", "ABCD"));
|
||||
|
||||
// Ordering.
|
||||
REQUIRE(!SubsequenceMatch("ad", "dcba"));
|
||||
REQUIRE(!SubsequenceMatchIgnoreCase("ad", "dcba"));
|
||||
}
|
||||
|
||||
TEST_CASE("skip") {
|
||||
@ -420,34 +413,33 @@ TEST_SUITE("LexFunctionDeclaration") {
|
||||
TEST_SUITE("LexWordAroundPos") {
|
||||
TEST_CASE("edges") {
|
||||
std::string content = "Foobar";
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'F'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'o'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'b'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'a'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'r'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'F'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'o'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'b'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'a'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'r'), content) == "Foobar");
|
||||
}
|
||||
|
||||
TEST_CASE("simple") {
|
||||
std::string content = " Foobar ";
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'F'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'o'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'b'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'a'), content) == "Foobar");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'r'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'F'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'o'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'b'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'a'), content) == "Foobar");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'r'), content) == "Foobar");
|
||||
}
|
||||
|
||||
TEST_CASE("underscores and numbers") {
|
||||
std::string content = " _my_t5ype7 ";
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '_'), content) == "_my_t5ype7");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '5'), content) == "_my_t5ype7");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, 'e'), content) == "_my_t5ype7");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '7'), content) == "_my_t5ype7");
|
||||
TEST_CASE("underscores, numbers and ::") {
|
||||
std::string content = " file:ns::_my_t5ype7 ";
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'f'), content) == "file");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 's'), content) == "ns");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, 'y'), content) == "ns::_my_t5ype7");
|
||||
}
|
||||
|
||||
TEST_CASE("dot, dash, colon are skipped") {
|
||||
std::string content = "1. 2- 3:";
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '1'), content) == "1");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '2'), content) == "2");
|
||||
REQUIRE(LexWordAroundPos(CharPos(content, '3'), content) == "3");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, '1'), content) == "1");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, '2'), content) == "2");
|
||||
REQUIRE(LexIdentifierAroundPos(CharPos(content, '3'), content) == "3");
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,11 @@ void LexFunctionDeclaration(const std::string& buffer_content,
|
||||
std::string* insert_text,
|
||||
int* newlines_after_name);
|
||||
|
||||
std::string LexWordAroundPos(lsPosition position, const std::string& content);
|
||||
std::string_view LexIdentifierAroundPos(lsPosition position,
|
||||
std::string_view content);
|
||||
|
||||
// Case-insensitive subsequence matching.
|
||||
bool SubsequenceMatch(std::string_view search, std::string_view content);
|
||||
bool SubsequenceMatchIgnoreCase(std::string_view search, std::string_view content);
|
||||
|
||||
std::tuple<bool, int> SubsequenceCountSkip(std::string_view search,
|
||||
std::string_view content);
|
||||
|
@ -447,8 +447,8 @@ struct TextDocumentCodeActionHandler
|
||||
// For error diagnostics, provide an action to resolve an include.
|
||||
// TODO: find a way to index diagnostic contents so line numbers
|
||||
// don't get mismatched when actively editing a file.
|
||||
std::string include_query =
|
||||
LexWordAroundPos(diag.range.start, working_file->buffer_content);
|
||||
std::string_view include_query =
|
||||
LexIdentifierAroundPos(diag.range.start, working_file->buffer_content);
|
||||
if (diag.severity == lsDiagnosticSeverity::Error &&
|
||||
!include_query.empty()) {
|
||||
const size_t kMaxResults = 20;
|
||||
|
@ -126,7 +126,7 @@ struct TextDocumentDefinitionHandler
|
||||
if (!has_symbol) {
|
||||
lsPosition position = request->params.position;
|
||||
const std::string& buffer = working_file->buffer_content;
|
||||
std::string query = LexWordAroundPos(position, buffer);
|
||||
std::string_view query = LexIdentifierAroundPos(position, buffer);
|
||||
bool has_scope = query.find(':') != std::string::npos;
|
||||
|
||||
// For symbols whose short/detailed names contain |query| as a
|
||||
|
@ -107,7 +107,7 @@ struct WorkspaceSymbolHandler : BaseMessageHandler<Ipc_WorkspaceSymbol> {
|
||||
|
||||
for (int i = 0; i < (int)db->symbols.size(); ++i) {
|
||||
std::string_view detailed_name = db->GetSymbolDetailedName(i);
|
||||
if (SubsequenceMatch(query_without_space, detailed_name)) {
|
||||
if (SubsequenceMatchIgnoreCase(query_without_space, detailed_name)) {
|
||||
// Do not show the same entry twice.
|
||||
if (!inserted_results.insert(std::string(detailed_name)).second)
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user