diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-23 16:49:49 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-23 16:52:00 +0200 |
commit | 426392f71d5f45aad8c57969643fd6c365ce2362 (patch) | |
tree | 3e5b6ddfc395e26f1a931f9a97516ede9b7c68d3 /sinksh/repl/replStates.cpp | |
parent | 1ec240e3df3e9c8571c0df174b9f239b451dbf3a (diff) | |
download | sink-426392f71d5f45aad8c57969643fd6c365ce2362.tar.gz sink-426392f71d5f45aad8c57969643fd6c365ce2362.zip |
Replaced readline with cpp-linenoise
... a single header readline replacement that works on all linux, osx
and windows (or so they claim). Besides cleaning up the code
considerably, it should help us build sinksh on windows where readline
is not really (there are some ancient broken readline ports) available.
cpp-readline comes from here: https://github.com/yhirose/cpp-linenoise
Diffstat (limited to 'sinksh/repl/replStates.cpp')
-rw-r--r-- | sinksh/repl/replStates.cpp | 68 |
1 files changed, 23 insertions, 45 deletions
diff --git a/sinksh/repl/replStates.cpp b/sinksh/repl/replStates.cpp index 18081df..c4b08b7 100644 --- a/sinksh/repl/replStates.cpp +++ b/sinksh/repl/replStates.cpp | |||
@@ -21,46 +21,54 @@ | |||
21 | 21 | ||
22 | #include <iostream> | 22 | #include <iostream> |
23 | 23 | ||
24 | #include <readline/readline.h> | ||
25 | #include <readline/history.h> | ||
26 | |||
27 | #include <QDebug> | 24 | #include <QDebug> |
28 | #include <QEvent> | 25 | #include <QEvent> |
29 | #include <QStateMachine> | 26 | #include <QStateMachine> |
27 | #include "linenoise.hpp" | ||
30 | 28 | ||
31 | #include "syntaxtree.h" | 29 | #include "syntaxtree.h" |
32 | 30 | ||
33 | static char *sink_cli_next_tab_complete_match(const char *text, int state); | ||
34 | static char ** sink_cli_tab_completion(const char *text, int start, int end); | ||
35 | |||
36 | ReadState::ReadState(QState *parent) | 31 | ReadState::ReadState(QState *parent) |
37 | : QState(parent) | 32 | : QState(parent) |
38 | { | 33 | { |
39 | rl_completion_entry_function = sink_cli_next_tab_complete_match; | 34 | linenoise::SetCompletionCallback([](const char* editBuffer, std::vector<std::string>& completions) { |
40 | rl_attempted_completion_function = sink_cli_tab_completion; | 35 | QStringList words = QString(editBuffer).split(" ", QString::SkipEmptyParts); |
36 | const QString fragment = words.takeLast(); | ||
37 | Syntax::List nearest = SyntaxTree::self()->nearestSyntax(words, fragment); | ||
38 | if (nearest.isEmpty()) { | ||
39 | SyntaxTree::Command command = SyntaxTree::self()->match(words); | ||
40 | if (command.first && command.first->completer) { | ||
41 | QStringList commandCompletions = command.first->completer(words, fragment, SyntaxTree::self()->state()); | ||
42 | for (const auto &c : commandCompletions) { | ||
43 | completions.push_back(c.toStdString()); | ||
44 | } | ||
45 | } | ||
46 | } else { | ||
47 | for (const auto &n : nearest) { | ||
48 | completions.push_back(n.keyword.toStdString()); | ||
49 | } | ||
50 | } | ||
51 | }); | ||
41 | } | 52 | } |
42 | 53 | ||
43 | void ReadState::onEntry(QEvent *event) | 54 | void ReadState::onEntry(QEvent *event) |
44 | { | 55 | { |
45 | Q_UNUSED(event) | 56 | Q_UNUSED(event) |
46 | char *line = readline(prompt()); | ||
47 | 57 | ||
48 | if (!line) { | 58 | std::string line; |
59 | if (linenoise::Readline(prompt(), line)) { | ||
49 | std::cout << std::endl; | 60 | std::cout << std::endl; |
50 | emit exitRequested(); | 61 | emit exitRequested(); |
51 | return; | 62 | return; |
52 | } | 63 | } |
53 | 64 | ||
54 | // we have actual data, so let's wait for a full line of text | 65 | // we have actual data, so let's wait for a full line of text |
55 | QByteArray input(line); | 66 | const QString text = QString::fromStdString(line).simplified(); |
56 | const QString text = QString(line).simplified(); | ||
57 | //qDebug() << "Line is ... " << text; | ||
58 | 67 | ||
59 | if (text.length() > 0) { | 68 | if (text.length() > 0) { |
60 | add_history(line); | 69 | linenoise::AddHistory(line.c_str()); |
61 | } | 70 | } |
62 | 71 | ||
63 | free(line); | ||
64 | emit command(text); | 72 | emit command(text); |
65 | } | 73 | } |
66 | 74 | ||
@@ -136,36 +144,6 @@ void PrintState::onEntry(QEvent *event) | |||
136 | emit completed(); | 144 | emit completed(); |
137 | } | 145 | } |
138 | 146 | ||
139 | static QStringList tab_completion_full_state; | ||
140 | static bool tab_completion_at_root = false; | ||
141 | |||
142 | static char **sink_cli_tab_completion(const char *text, int start, int end) | ||
143 | { | ||
144 | tab_completion_at_root = start == 0; | ||
145 | tab_completion_full_state = QString(rl_line_buffer).remove(start, end - start).split(" ", QString::SkipEmptyParts); | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | static char *sink_cli_next_tab_complete_match(const char *text, int state) | ||
150 | { | ||
151 | const QString fragment(text); | ||
152 | Syntax::List nearest = SyntaxTree::self()->nearestSyntax(tab_completion_full_state, fragment); | ||
153 | //for (auto syntax: nearest) { qDebug() << "Nearest: " << syntax.keyword; } | ||
154 | |||
155 | if (nearest.isEmpty()) { | ||
156 | SyntaxTree::Command command = SyntaxTree::self()->match(tab_completion_full_state); | ||
157 | if (command.first && command.first->completer) { | ||
158 | QStringList commandCompletions = command.first->completer(tab_completion_full_state, fragment, SyntaxTree::self()->state()); | ||
159 | if (commandCompletions.size() > state) { | ||
160 | return qstrdup(commandCompletions[state].toUtf8()); | ||
161 | } | ||
162 | } | ||
163 | } else if (nearest.size() > state) { | ||
164 | return qstrdup(nearest[state].keyword.toUtf8()); | ||
165 | } | ||
166 | |||
167 | return rl_filename_completion_function(text, state); | ||
168 | } | ||
169 | 147 | ||
170 | //Ignore warning I don't know how to fix in a moc file | 148 | //Ignore warning I don't know how to fix in a moc file |
171 | #pragma clang diagnostic push | 149 | #pragma clang diagnostic push |