Files
integration/luprex/cpp/drv/readline.cpp

112 lines
3.2 KiB
C++
Raw Normal View History

#include "readline.hpp"
#define MAXLINE 512
2023-05-19 00:23:23 -04:00
static std::u32string n_backspaces(int n) {
std::u32string result(3 * n, 0);
for (int i = 0; i < n; i++) {
result[i*3 + 0] = '\b';
result[i*3 + 1] = ' ';
result[i*3 + 2] = '\b';
}
return result;
}
2023-05-19 00:23:23 -04:00
static int common_prefix_length(const std::u32string &a, const std::u32string &b) {
int minlen = std::min(a.size(), b.size());
for (int i = 0; i < minlen; i++) {
if (a[i] != b[i]) return i;
}
return minlen;
}
void ReadlineDevice::set_print_callback(print_callback cb) {
print_cb_ = cb;
}
2023-05-19 00:23:23 -04:00
void ReadlineDevice::set_prompt(const std::u32string &prompt) {
desired_prompt_ = prompt;
echo_command();
}
void ReadlineDevice::erase_command() {
int ccsize = current_prompt_.size() + current_command_.size();
if (ccsize > 0) {
print_cb_(n_backspaces(ccsize));
current_prompt_.clear();
current_command_.clear();
}
}
void ReadlineDevice::echo_command() {
// If the prompt has changed, erase everything and start over.
if (desired_prompt_ != current_prompt_) {
int ccsize = current_prompt_.size() + current_command_.size();
print_cb_(n_backspaces(ccsize));
print_cb_(desired_prompt_);
current_command_.clear();
current_prompt_ = desired_prompt_;
}
// Find out how much of the command matches.
int match = common_prefix_length(current_command_, desired_command_);
// Echo backspaces to remove the non-matching part.
int remove = current_command_.size() - match;
if (remove > 0) {
print_cb_(n_backspaces(remove));
current_command_ = current_command_.substr(0, match);
}
// Echo the new part.
2023-05-19 00:23:23 -04:00
std::u32string newpart = desired_command_.substr(current_command_.size());
if (!newpart.empty()) {
print_cb_(newpart);
current_command_ = desired_command_;
}
}
2023-05-19 00:23:23 -04:00
std::u32string ReadlineDevice::putcode(char32_t c) {
if ((c == '\n') && (readline_lastc_ == '\r')) {
// Ignore newline immediately after carriage return.
// Otherwise, crlf produces two newlines.
2023-05-19 00:23:23 -04:00
return std::u32string();
} else if ((c == '\r') || (c == '\n')) {
2023-05-19 00:23:23 -04:00
std::u32string white(1, ' ');
std::u32string newline(1, '\n');
echo_command();
print_cb_(white + newline);
2023-05-19 00:23:23 -04:00
std::u32string result = desired_command_ + newline;
desired_command_.clear();
current_prompt_.clear();
current_command_.clear();
echo_command();
return result;
} else if ((c == '\b') || (c == 127)) {
int len = desired_command_.size();
if (len > 0) {
desired_command_ = desired_command_.substr(0, len-1);
}
echo_command();
2023-05-19 00:23:23 -04:00
return std::u32string();
} else if ((c >= 32)&&(c <= 0x10FFFF)) {
int len = desired_command_.size();
if (len < MAXLINE) {
desired_command_ = desired_command_ + c;
}
echo_command();
2023-05-19 00:23:23 -04:00
return std::u32string();
}
readline_lastc_ = c;
2023-05-19 00:23:23 -04:00
return std::u32string();
}
2023-05-19 00:23:23 -04:00
void ReadlineDevice::print(const std::u32string &s) {
if (!s.empty()) {
erase_command();
print_cb_(s);
echo_command();
}
}