125 lines
3.3 KiB
C++
125 lines
3.3 KiB
C++
#include "internal/ui/command.h"
|
|
#include "bed.h"
|
|
#include "internal/parser/parser.h"
|
|
|
|
namespace bed::internal::ui {
|
|
CommandIO::CommandIO(BEd &bed) : bed(bed) {
|
|
if (bed.prompt_mode)
|
|
prompt = bed.prompt(bed);
|
|
cursor = 0;
|
|
}
|
|
|
|
std::pair<std::string, bool> CommandIO::run() {
|
|
if (!bed.io.interactive())
|
|
return run_pipe();
|
|
return run_terminal();
|
|
}
|
|
|
|
std::pair<std::string, bool> CommandIO::run_pipe() {
|
|
bed.io.write(prompt);
|
|
return bed.io.read_pipe();
|
|
}
|
|
|
|
std::pair<std::string, bool> CommandIO::run_terminal() {
|
|
auto [row, col] = bed.io.cursor_position();
|
|
auto [rows, cols] = bed.io.terminal_size();
|
|
if (row > rows)
|
|
throw fatal_error("Invalid cursor position.", 1);
|
|
start = row;
|
|
height = rows - row + 1;
|
|
term_width = cols;
|
|
term_height = rows;
|
|
redraw();
|
|
|
|
io::KeyEvent res;
|
|
bool running = true;
|
|
while (running) {
|
|
res = bed.io.read_key();
|
|
switch (res.type) {
|
|
case io::KeyEvent::KeyType::EOF_:
|
|
running = false;
|
|
break;
|
|
case io::KeyEvent::KeyType::MOUSE:
|
|
case io::KeyEvent::KeyType::RESIZE:
|
|
break;
|
|
case io::KeyEvent::KeyType::CHAR:
|
|
switch (res.modifier) {
|
|
case io::KeyEvent::Modifier::SHIFT:
|
|
case io::KeyEvent::Modifier::ALT:
|
|
case io::KeyEvent::Modifier::CTRL_ALT:
|
|
case io::KeyEvent::Modifier::CTRL:
|
|
break;
|
|
case io::KeyEvent::Modifier::NONE:
|
|
if (res.text[0] == '\b' || res.text[0] == 0x7f) {
|
|
if (cursor > 0)
|
|
cmd.erase(--cursor, 1);
|
|
} else if (res.text[0] == '\n') {
|
|
running = false;
|
|
} else {
|
|
cmd.insert(cursor++, res.text);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case io::KeyEvent::KeyType::PASTE:
|
|
cmd.insert(cursor, res.text);
|
|
cursor += res.text.size();
|
|
break;
|
|
case io::KeyEvent::KeyType::SPECIAL:
|
|
switch (res.special_key) {
|
|
case io::KeyEvent::SpecialKey::UNKNOWN:
|
|
case io::KeyEvent::SpecialKey::UP:
|
|
case io::KeyEvent::SpecialKey::DOWN:
|
|
break;
|
|
case io::KeyEvent::SpecialKey::RIGHT:
|
|
if (cursor < cmd.size())
|
|
cursor++;
|
|
break;
|
|
case io::KeyEvent::SpecialKey::LEFT:
|
|
if (cursor > 0)
|
|
cursor--;
|
|
break;
|
|
case io::KeyEvent::SpecialKey::DELETE:
|
|
if (cursor < cmd.size())
|
|
cmd.erase(cursor, 1);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
redraw();
|
|
}
|
|
|
|
for (uint16_t i = 1; i < height; ++i) {
|
|
bed.io.move_cursor(start + i, 1);
|
|
bed.io.write("\x1b[2K", 4);
|
|
}
|
|
bed.io.move_cursor(start, 1);
|
|
bed.io.write("\n", 1);
|
|
return {cmd, false};
|
|
}
|
|
|
|
void CommandIO::redraw() {
|
|
bed.io.move_cursor(start, 1);
|
|
bed.io.write("\x1b[2K", 4);
|
|
bed.io.move_cursor(start, 1);
|
|
bed.io.write(prompt);
|
|
const auto tokens = parser::Parser::get_highlight(cmd, bed);
|
|
uint32_t pos = 0;
|
|
for (const auto &token : tokens) {
|
|
const uint32_t tstart = token.start;
|
|
const uint32_t tend = token.end;
|
|
if (tstart > cmd.size())
|
|
break;
|
|
if (pos < tstart)
|
|
bed.io.write(cmd.data() + pos, tstart - pos);
|
|
bed.io.apply(token.type);
|
|
bed.io.write(cmd.data() + tstart, tend - tstart);
|
|
bed.io.reset();
|
|
pos = tend;
|
|
}
|
|
if (pos < cmd.size())
|
|
bed.io.write(cmd.data() + pos, cmd.size() - pos);
|
|
bed.io.move_cursor(start, prompt.size() + cursor + 1);
|
|
}
|
|
} // namespace bed::internal::ui
|