diff options
author | vityaman <vityaman.dev@yandex.ru> | 2025-05-06 15:49:02 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2025-05-06 16:04:08 +0300 |
commit | 9c3fdca51d8ae892c5ad8f6ef92df73fafc09e28 (patch) | |
tree | 561c599fae4ea29b537a6958b65e1b052548edf2 /yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp | |
parent | c131e959456f9f9a4adada5623ce3bae4097a8c1 (diff) | |
download | ydb-9c3fdca51d8ae892c5ad8f6ef92df73fafc09e28.tar.gz |
YQL-19747 Complete folder, table and cluster names
---
- Related to `YQL-19747`
- On top of https://github.com/ytsaurus/ytsaurus/pull/1253
- Related to https://github.com/ydb-platform/ydb/issues/9056
- Related to https://github.com/vityaman/ydb/issues/14
- Related to https://github.com/vityaman/ydb/issues/35
- Related to https://github.com/vityaman/ydb/issues/40
---
Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1257
commit_hash:0b842abb27184c88b8177beeea29fb1ea86b7a04
Diffstat (limited to 'yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp')
-rw-r--r-- | yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp b/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp new file mode 100644 index 00000000000..33aef36847a --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp @@ -0,0 +1,160 @@ +#include "cursor_token_context.h" + +#include <yql/essentials/core/issue/yql_issue.h> +#include <yql/essentials/sql/v1/lexer/lexer.h> + +namespace NSQLComplete { + + namespace { + + bool Tokenize(ILexer::TPtr& lexer, TCompletionInput input, TParsedTokenList& tokens) { + NYql::TIssues issues; + if (!NSQLTranslation::Tokenize( + *lexer, TString(input.Text), /* queryName = */ "", + tokens, issues, /* maxErrors = */ 1)) { + return false; + } + return true; + } + + TCursor GetCursor(const TParsedTokenList& tokens, size_t cursorPosition) { + size_t current = 0; + for (size_t i = 0; i < tokens.size() && current < cursorPosition; ++i) { + const auto& content = tokens[i].Content; + + current += content.size(); + if (current < cursorPosition) { + continue; + } + + TCursor cursor = { + .PrevTokenIndex = i, + .NextTokenIndex = i, + .Position = cursorPosition, + }; + + if (current == cursorPosition) { + cursor.NextTokenIndex += 1; + } + + return cursor; + } + + return { + .PrevTokenIndex = Nothing(), + .NextTokenIndex = 0, + .Position = cursorPosition, + }; + } + + TVector<size_t> GetTokenPositions(const TParsedTokenList& tokens) { + TVector<size_t> positions; + positions.reserve(tokens.size()); + size_t pos = 0; + for (const auto& token : tokens) { + positions.emplace_back(pos); + pos += token.Content.size(); + } + return positions; + } + + } // namespace + + bool TRichParsedToken::IsLiteral() const { + return Base->Name == "STRING_VALUE" || + Base->Name == "DIGIGTS" || + Base->Name == "INTEGER_VALUE" || + Base->Name == "REAL"; + } + + TRichParsedToken TokenAt(const TCursorTokenContext& context, size_t index) { + return { + .Base = &context.Tokens.at(index), + .Index = index, + .Position = context.TokenPositions.at(index), + }; + } + + TMaybe<TRichParsedToken> TCursorTokenContext::Enclosing() const { + if (Tokens.size() == 1) { + Y_ENSURE(Tokens[0].Name == "EOF"); + return Nothing(); + } + + if (Cursor.PrevTokenIndex.Empty()) { + return Nothing(); + } + + auto token = TokenAt(*this, *Cursor.PrevTokenIndex); + if (Cursor.PrevTokenIndex == Cursor.NextTokenIndex || + !IsWordBoundary(token.Base->Content.back())) { + return token; + } + + return Nothing(); + } + + TMaybe<TRichParsedToken> TCursorTokenContext::MatchCursorPrefix(const TVector<TStringBuf>& pattern) const { + const auto prefix = std::span{Tokens.begin(), Cursor.NextTokenIndex}; + if (prefix.size() < pattern.size()) { + return Nothing(); + } + + ssize_t i = static_cast<ssize_t>(prefix.size()) - 1; + ssize_t j = static_cast<ssize_t>(pattern.size()) - 1; + for (; 0 <= j; --i, --j) { + if (!pattern[j].empty() && prefix[i].Name != pattern[j]) { + return Nothing(); + } + } + return TokenAt(*this, prefix.size() - pattern.size()); + } + + bool GetStatement( + ILexer::TPtr& lexer, + TCompletionInput input, + TCompletionInput& output, + size_t& output_position) { + TVector<TString> statements; + NYql::TIssues issues; + if (!NSQLTranslationV1::SplitQueryToStatements( + TString(input.Text) + ";", lexer, + statements, issues, /* file = */ "", + /* areBlankSkipped = */ false)) { + return false; + } + + size_t& cursor = output_position; + cursor = 0; + for (const auto& statement : statements) { + if (input.CursorPosition < cursor + statement.size()) { + output = { + .Text = input.Text.SubStr(cursor, statement.size()), + .CursorPosition = input.CursorPosition - cursor, + }; + return true; + } + cursor += statement.size(); + } + + output = input; + return true; + } + + bool GetCursorTokenContext(ILexer::TPtr& lexer, TCompletionInput input, TCursorTokenContext& context) { + TParsedTokenList tokens; + if (!Tokenize(lexer, input, tokens)) { + return false; + } + + TVector<size_t> positions = GetTokenPositions(tokens); + TCursor cursor = GetCursor(tokens, input.CursorPosition); + context = { + .Tokens = std::move(tokens), + .TokenPositions = std::move(positions), + .Cursor = cursor, + }; + return true; + } + +} // namespace NSQLComplete |