#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 CommandIO::run() { if (!bed.io.interactive()) return run_pipe(); return run_terminal(); } std::pair CommandIO::run_pipe() { bed.io.write(prompt); return bed.io.read_pipe(); } std::pair 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