mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Fix \G in clickhouse-client multiline mode #9933
This commit is contained in:
parent
92ac608447
commit
1bbbfc6e1b
@ -67,8 +67,8 @@ LineReader::Suggest::WordsRange LineReader::Suggest::getCompletions(const String
|
||||
});
|
||||
}
|
||||
|
||||
LineReader::LineReader(const String & history_file_path_, char extender_, char delimiter_)
|
||||
: history_file_path(history_file_path_), extender(extender_), delimiter(delimiter_)
|
||||
LineReader::LineReader(const String & history_file_path_, bool multiline_, Patterns extenders_, Patterns delimiters_)
|
||||
: history_file_path(history_file_path_), multiline(multiline_), extenders(std::move(extenders_)), delimiters(std::move(delimiters_))
|
||||
{
|
||||
/// FIXME: check extender != delimiter
|
||||
}
|
||||
@ -76,38 +76,60 @@ LineReader::LineReader(const String & history_file_path_, char extender_, char d
|
||||
String LineReader::readLine(const String & first_prompt, const String & second_prompt)
|
||||
{
|
||||
String line;
|
||||
bool is_multiline = false;
|
||||
bool need_next_line = false;
|
||||
|
||||
while (auto status = readOneLine(is_multiline ? second_prompt : first_prompt))
|
||||
while (auto status = readOneLine(need_next_line ? second_prompt : first_prompt))
|
||||
{
|
||||
if (status == RESET_LINE)
|
||||
{
|
||||
line.clear();
|
||||
is_multiline = false;
|
||||
need_next_line = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input.empty())
|
||||
{
|
||||
if (!line.empty() && !delimiter && !hasInputData())
|
||||
if (!line.empty() && !multiline && !hasInputData())
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
is_multiline = (input.back() == extender) || (delimiter && input.back() != delimiter) || hasInputData();
|
||||
|
||||
if (input.back() == extender)
|
||||
#if !defined(ARCADIA_BUILD) /// C++20
|
||||
const char * has_extender = nullptr;
|
||||
for (const auto * extender : extenders)
|
||||
{
|
||||
input = input.substr(0, input.size() - 1);
|
||||
if (input.ends_with(extender))
|
||||
{
|
||||
has_extender = extender;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char * has_delimiter = nullptr;
|
||||
for (const auto * delimiter : delimiters)
|
||||
{
|
||||
if (input.ends_with(delimiter))
|
||||
{
|
||||
has_delimiter = delimiter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
need_next_line = has_extender || (multiline && !has_delimiter) || hasInputData();
|
||||
|
||||
if (has_extender)
|
||||
{
|
||||
input.resize(input.size() - strlen(has_extender));
|
||||
trim(input);
|
||||
if (input.empty())
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
line += (line.empty() ? "" : " ") + input;
|
||||
|
||||
if (!is_multiline)
|
||||
if (!need_next_line)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,10 @@ public:
|
||||
WordsRange getCompletions(const String & prefix, size_t prefix_length) const;
|
||||
};
|
||||
|
||||
LineReader(const String & history_file_path, char extender, char delimiter = 0); /// if delimiter != 0, then it's multiline mode
|
||||
using Patterns = std::vector<const char *>;
|
||||
|
||||
/// if delimiter is set, then it's multiline mode
|
||||
LineReader(const String & history_file_path, bool multiline, Patterns extenders, Patterns delimiters);
|
||||
virtual ~LineReader() {}
|
||||
|
||||
/// Reads the whole line until delimiter (in multiline mode) or until the last line without extender.
|
||||
@ -51,8 +54,10 @@ protected:
|
||||
String input;
|
||||
|
||||
private:
|
||||
const char extender;
|
||||
const char delimiter;
|
||||
bool multiline;
|
||||
|
||||
Patterns extenders;
|
||||
Patterns delimiters;
|
||||
|
||||
String prev_line;
|
||||
|
||||
|
@ -56,8 +56,9 @@ static char * generate(const char * text, int state)
|
||||
return nextMatch();
|
||||
};
|
||||
|
||||
ReadlineLineReader::ReadlineLineReader(const Suggest & suggest_, const String & history_file_path_, char extender_, char delimiter_)
|
||||
: LineReader(history_file_path_, extender_, delimiter_)
|
||||
ReadlineLineReader::ReadlineLineReader(
|
||||
const Suggest & suggest_, const String & history_file_path_, bool multiline_, Patterns extender_, Patterns delimiter_)
|
||||
: LineReader(history_file_path_, multiline_, std::move(extender_), std::move(delimiter_))
|
||||
{
|
||||
suggest = &suggest_;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
class ReadlineLineReader : public LineReader
|
||||
{
|
||||
public:
|
||||
ReadlineLineReader(const Suggest & suggest, const String & history_file_path, char extender, char delimiter = 0);
|
||||
ReadlineLineReader(const Suggest & suggest, const String & history_file_path, bool multiline, Patterns extender_, Patterns delimiter_);
|
||||
~ReadlineLineReader() override;
|
||||
|
||||
void enableBracketedPaste() override;
|
||||
|
@ -16,8 +16,9 @@ void trim(String & s)
|
||||
|
||||
}
|
||||
|
||||
ReplxxLineReader::ReplxxLineReader(const Suggest & suggest, const String & history_file_path_, char extender_, char delimiter_)
|
||||
: LineReader(history_file_path_, extender_, delimiter_)
|
||||
ReplxxLineReader::ReplxxLineReader(
|
||||
const Suggest & suggest, const String & history_file_path_, bool multiline_, Patterns extender_, Patterns delimiter_)
|
||||
: LineReader(history_file_path_, multiline_, std::move(extender_), std::move(delimiter_))
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
using Replxx = replxx::Replxx;
|
||||
|
@ -7,7 +7,7 @@
|
||||
class ReplxxLineReader : public LineReader
|
||||
{
|
||||
public:
|
||||
ReplxxLineReader(const Suggest & suggest, const String & history_file_path, char extender, char delimiter = 0);
|
||||
ReplxxLineReader(const Suggest & suggest, const String & history_file_path, bool multiline, Patterns extenders_, Patterns delimiter_);
|
||||
~ReplxxLineReader() override;
|
||||
|
||||
void enableBracketedPaste() override;
|
||||
|
@ -498,12 +498,15 @@ private:
|
||||
if (!history_file.empty() && !Poco::File(history_file).exists())
|
||||
Poco::File(history_file).createFile();
|
||||
|
||||
LineReader::Patterns query_extenders = {"\\"};
|
||||
LineReader::Patterns query_delimiters = {";", "\\G"};
|
||||
|
||||
#if USE_REPLXX
|
||||
ReplxxLineReader lr(Suggest::instance(), history_file, '\\', config().has("multiline") ? ';' : 0);
|
||||
ReplxxLineReader lr(Suggest::instance(), history_file, config().has("multiline"), query_extenders, query_delimiters);
|
||||
#elif defined(USE_READLINE) && USE_READLINE
|
||||
ReadlineLineReader lr(Suggest::instance(), history_file, '\\', config().has("multiline") ? ';' : 0);
|
||||
ReadlineLineReader lr(Suggest::instance(), history_file, config().has("multiline"), query_extenders, query_delimiters);
|
||||
#else
|
||||
LineReader lr(history_file, '\\', config().has("multiline") ? ';' : 0);
|
||||
LineReader lr(history_file, config().has("multiline"), query_extenders, query_delimiters);
|
||||
#endif
|
||||
|
||||
/// Enable bracketed-paste-mode only when multiquery is enabled and multiline is
|
||||
|
Loading…
Reference in New Issue
Block a user