From a423cd8bb35ba8e86f2f83deabdf9ff9fd5aac4a Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 5 Apr 2023 01:30:58 +0300 Subject: [PATCH] Kernel: Add partial support for shell We don't handle arrow keys, and the tty does not know how to clear the screeen :D --- kernel/include/kernel/Shell.h | 3 +- kernel/include/kernel/Terminal/TTY.h | 1 + kernel/kernel/Shell.cpp | 182 +++++---------------------- kernel/kernel/Terminal/TTY.cpp | 18 ++- kernel/kernel/kernel.cpp | 17 +-- 5 files changed, 46 insertions(+), 175 deletions(-) diff --git a/kernel/include/kernel/Shell.h b/kernel/include/kernel/Shell.h index 614e49a496..764137ed8c 100644 --- a/kernel/include/kernel/Shell.h +++ b/kernel/include/kernel/Shell.h @@ -19,10 +19,9 @@ namespace Kernel void rerender_buffer() const; BAN::Vector parse_arguments(BAN::StringView) const; BAN::ErrorOr process_command(const BAN::Vector&); - void key_event_callback(Input::KeyEvent); BAN::ErrorOr update_prompt(); - private: + private: BAN::Vector m_old_buffer; BAN::Vector m_buffer; BAN::String m_prompt_string; diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index f2e197115d..4958736ccd 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -39,6 +39,7 @@ namespace Kernel void render_from_buffer(uint32_t x, uint32_t y); void on_key(Input::KeyEvent); + void do_backspace(); private: enum class State diff --git a/kernel/kernel/Shell.cpp b/kernel/kernel/Shell.cpp index 3e75360843..b39e0aecb1 100644 --- a/kernel/kernel/Shell.cpp +++ b/kernel/kernel/Shell.cpp @@ -11,11 +11,23 @@ #include #include -#include #include +#include +#include + +#define TTY_PRINT(...) \ + do { \ + BAN::String message_ = BAN::String::formatted(__VA_ARGS__); \ + MUST(Process::current()->write(STDOUT_FILENO, message_.data(), message_.size())); \ + } while (false) + +#define TTY_PRINTLN(...) \ + do { \ + TTY_PRINT(__VA_ARGS__); \ + MUST(Process::current()->write(STDOUT_FILENO, "\n", 1)); \ + } while (false) + -#define TTY_PRINT(...) -#define TTY_PRINTLN(...) namespace Kernel { @@ -99,17 +111,22 @@ namespace Kernel void Shell::run() { - int fd = MUST(Process::current()->open("/dev/tty1"sv, O_RDONLY)); - TTY_PRINT("{}", m_prompt); + BAN::String input; for (;;) { - uint8_t buffer[128]; - size_t n_read = MUST(Process::current()->read(fd, buffer, sizeof(buffer))); - dprintln("{}", BAN::StringView((const char*)buffer, n_read)); - //Input::KeyEvent event; - //MUST(Process::current()->read(fd, &event, sizeof(event))); - //key_event_callback(event); + char buffer[128]; + size_t n_read = MUST(Process::current()->read(STDIN_FILENO, buffer, sizeof(buffer))); + + MUST(input.append(BAN::StringView(buffer, n_read))); + if (input.back() == '\n') + { + input.pop_back(); + if (auto res = process_command(parse_arguments(input)); res.is_error()) + TTY_PRINTLN("{}", res.error()); + TTY_PRINT("{}", m_prompt); + input.clear(); + } } } @@ -540,147 +557,4 @@ argument_done: TTY_PRINT("\e[{}G{}\e[K", m_prompt_length + 1, m_buffer[m_cursor_pos.line]); } - static uint32_t get_last_length(BAN::StringView sv) - { - if (sv.size() >= 2 && ((uint8_t)sv[sv.size() - 2] >> 5) == 0b110) return 2; - if (sv.size() >= 3 && ((uint8_t)sv[sv.size() - 3] >> 4) == 0b1110) return 3; - if (sv.size() >= 4 && ((uint8_t)sv[sv.size() - 4] >> 3) == 0b11110) return 4; - return BAN::Math::min(sv.size(), 1); - } - - static uint32_t get_next_length(BAN::StringView sv) - { - if (sv.size() >= 2 && ((uint8_t)sv[0] >> 5) == 0b110) return 2; - if (sv.size() >= 3 && ((uint8_t)sv[0] >> 4) == 0b1110) return 3; - if (sv.size() >= 4 && ((uint8_t)sv[0] >> 3) == 0b11110) return 4; - return BAN::Math::min(sv.size(), 1); - } - - static uint32_t get_unicode_character_count(BAN::StringView sv) - { - uint32_t len = 0; - for (uint32_t i = 0; i < sv.size(); i++) - { - uint8_t ch = sv[i]; - if ((ch >> 5) == 0b110) i += 1; - if ((ch >> 4) == 0b1110) i += 2; - if ((ch >> 3) == 0b11110) i += 3; - len++; - } - return len; - } - - void Shell::key_event_callback(Input::KeyEvent event) - { - if (event.released()) - return; - - BAN::String& current_buffer = m_buffer[m_cursor_pos.line]; - - switch (event.key) - { - case Input::Key::Backspace: - if (m_cursor_pos.col > 0) - { - TTY_PRINT("\e[D{} ", current_buffer.sv().substring(m_cursor_pos.index)); - - uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index)); - m_cursor_pos.index -= len; - current_buffer.erase(m_cursor_pos.index, len); - m_cursor_pos.col--; - } - break; - - case Input::Key::Enter: - case Input::Key::NumpadEnter: - { - TTY_PRINTLN(""); - auto arguments = parse_arguments(current_buffer.sv()); - if (!arguments.empty()) - { - if (auto res = process_command(arguments); res.is_error()) - TTY_PRINTLN("{}", res.error()); - MUST(m_old_buffer.push_back(current_buffer)); - m_buffer = m_old_buffer; - MUST(m_buffer.push_back(""sv)); - m_cursor_pos.line = m_buffer.size() - 1; - } - m_cursor_pos.col = 0; - m_cursor_pos.index = 0; - TTY_PRINT("{}", m_prompt); - break; - } - - case Input::Key::Escape: - TTY_PRINTLN("time since boot {} ms", PIT::ms_since_boot()); - break; - - case Input::Key::Tab: - break; - - case Input::Key::ArrowLeft: - if (m_cursor_pos.index > 0) - { - uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index)); - m_cursor_pos.index -= len; - m_cursor_pos.col--; - } - break; - - case Input::Key::ArrowRight: - if (m_cursor_pos.index < current_buffer.size()) - { - uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index)); - m_cursor_pos.index += len; - m_cursor_pos.col++; - } - break; - - case Input::Key::ArrowUp: - if (m_cursor_pos.line > 0) - { - const auto& new_buffer = m_buffer[m_cursor_pos.line - 1]; - m_cursor_pos.line--; - m_cursor_pos.index = new_buffer.size(); - m_cursor_pos.col = get_unicode_character_count(new_buffer); - rerender_buffer(); - } - break; - - case Input::Key::ArrowDown: - if (m_cursor_pos.line < m_buffer.size() - 1) - { - const auto& new_buffer = m_buffer[m_cursor_pos.line + 1]; - m_cursor_pos.line++; - m_cursor_pos.index = new_buffer.size(); - m_cursor_pos.col = get_unicode_character_count(new_buffer); - rerender_buffer(); - } - break; - - case Input::Key::A: - if (event.ctrl()) - { - m_cursor_pos.col = m_cursor_pos.index = 0; - break; - } - // fall through - - default: - { - const char* utf8 = Input::key_event_to_utf8(event); - if (utf8) - { - TTY_PRINT("{}{}", utf8, current_buffer.sv().substring(m_cursor_pos.index)); - MUST(current_buffer.insert(utf8, m_cursor_pos.index)); - m_cursor_pos.index += strlen(utf8); - m_cursor_pos.col++; - } - break; - } - } - - //TTY_PRINT("\e[{}G", (m_prompt_length + m_cursor_pos.col) % m_tty->width() + 1); - } - } \ No newline at end of file diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index db41bf2421..240c80921f 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -92,6 +92,7 @@ namespace Kernel ansi = "\n"; break; case Input::Key::Backspace: + ansi = nullptr; if (m_output.bytes > 0) { // Multibyte UTF8 @@ -103,19 +104,20 @@ namespace Kernel ASSERT(m_output.bytes > 0); m_output.bytes--; } - ansi = "\b \b"; + do_backspace(); } // Control sequence else if (m_output.bytes >= 2 && m_output.buffer[m_output.bytes - 2] == '\e') { m_output.bytes -= 2; - ansi = "\b\b \b\b"; + do_backspace(); + do_backspace(); } // Ascii else { m_output.bytes--; - ansi = "\b \b"; + do_backspace(); } } break; @@ -156,6 +158,16 @@ namespace Kernel m_terminal_driver->clear(m_background); } + void TTY::do_backspace() + { + if (m_column > 0) + { + m_column--; + putchar_at(' ', m_column, m_row); + set_cursor_position(m_column, m_row); + } + } + void TTY::set_cursor_position(uint32_t x, uint32_t y) { static uint32_t last_x = -1; diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 8a85b73fdc..e20bedf7c6 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -222,25 +222,10 @@ static void init2(void* terminal_driver) ASSERT(tty1); DeviceManager::get().add_device(tty1); - MUST(Process::create_kernel( - [](void*) - { - MUST(Process::current()->init_stdio()); - while (true) - { - char buffer[1024]; - int n_read = MUST(Process::current()->read(STDIN_FILENO, buffer, sizeof(buffer))); - MUST(Process::current()->write(STDOUT_FILENO, buffer, n_read)); - dprintln("{} bytes", n_read); - } - }, nullptr - )); - - return; - MUST(Process::create_kernel( [](void*) { + MUST(Process::current()->init_stdio()); Shell* shell = new Shell(); ASSERT(shell); shell->run();